Laravel 图片处理扩展包intervention/image的基本使用

首先是安装:

composer require intervention/image

安装他需要你的 php版本大于等于 5.4
还需要有 fileinfo 扩展,你可以通过 phpinfo() 查看扩展是否安装,也可以通过命令:

php --ri fileinfo 查看

我使用的是 lnmp 1.4 的一键安装,没有 fileinfo扩展
那么首先安装这个扩展:

1.首先确认你的系统中有 fileinfo 这个扩展源码,可以使用find 查找

find / -name fileinfo

2.如果没有,那么你可以再去php官网下载一份和你的php版本对应的源安装包
例如我的是 php 5.6.31

wget http://cn2.php.net/get/php-5.6.31.tar.gz/from/this/mirror
mv mirror php-5.6.31.tar.gz
tar -zxvf php-5.6.31.tar.gz
cd php-5.6.31/ext/fileinfo

此时就在 fileinfo 目录了。
3.你可以在这里直接执行命令

phpize

就会看到 configure文件
4.再执行如下命令:

./configure --with-php-config=/usr/local/php/bin/php-config
make && make install

此时完成了 fileinfo 扩展的编译工作
5.添加 fileinfo 到到 php.ini
修改 php.ini 添加 `extension=fileinfo.so`
6.重启 php-fpm 和 nginx 完成 fileinfo 扩展的安装

此时再执行

composer require intervention/image

就不会报错了
接下来laravel 添加这个服务
修改 config/app.php 在 providers 添加

Intervention\Image\ImageServiceProvider::class,

在 aliases 中添加

'Image' => Intervention\Image\Facades\Image::class,

这样就可以在 controller 里使用了

use Image;
// ...
// 代码
// ...
$img = Image::make('upload/a.png')->resize(50,100);  //修改尺寸
if(file_exists(public_path('new_image/'))){
}
else{
mkdir ( public_path('new_image/'), 0777);
}
$img->save('new_image/a_new.png',75); // 保存到别的路径,第二个参数设置压缩质量

上面的 make 传参是图片路径,这个路径是public 下的路径
在save 的时候首先要判断目录存在,如果不存在需要先创建,否则报错。如果是好几层的目录需要递归创建
参考函数:

public static function mkMutiDir($dir){
if(!is_dir($dir)){
if(!self::mkMutiDir(dirname($dir))){
return false;
}
if(!mkdir($dir,0777)){
return false;
}
}
return true;
}

Image::make 接收的参数不局限于图片文件 具体参考:
http://image.intervention.io/api/make
所以在 Laravel 中上传的文件也可以直接 make

$file = $request->file('img');
$img = Image::make($file);
//...

接下来你可以参考api 文档根据实际使用啦!

 

laravel composer 扩展包开发(超详细)

laravel composer package develop
文章适用于laravel 包开发,当然如果你理解着完成一遍,就可以发现他也适用于 composer 扩展包开发,不是必须在laravel 下。
首先在 laravel 根目录创建文件夹 packages 这里放置我们准备创建的扩展包,这个目录只是暂时存放我们的扩展包代码,等我们开发完成配置好了,就不需要他了。
当然如果你不需要发布你的包,以后也可以就使用这个目录。packages 目录和 laravel 的 app 目录同级
然后进入packages 创建目录  aex 当然这个名字可以随意起(最好是作者的名之类的),
接着进入 aex 目录创建目录 packagetest 这个目录的名称最好是你的扩展包名称,有点意义。 我就是为了测试,所以就叫做 packagetest 好了
然后创建目录 src 这里就是我们放置代码的地方啦。
接着命令行下进入 packages/aex/packagetest 执行 composer init  他会一步步询问你要填写的信息:
1
执行完成你会在 packagetest 目录下看到 composer.json 内容和上图一致。 当然其实你也可以直接复制一个 composer.json 不需要 composer init
我的 composer.json 内容如下:
{
    "name": "aex/packagetest-for-laravel",
    "authors": [
        {
            "name": "aex",
            "email": "email@email.com"
        }
    ],
    "require": {}
}
你也可以根据 composer.json 的规则添加相应的其它配置
目前目录结构是这样的:
2
虽然你知道代码都在 src目录下,但是 laravel 不知道,所以你要告诉他,即配置 laravel 根目录的 composer.json
修改 autoload 改为类似如下:
"autoload": {
    "classmap": [
        "database"
    ],
    "psr-4": {
        "App\\": "app/",
        "Aex\\Packagetest\\": "packages/aex/packagetest/src/"
    }
},
然后创建服务:使用 artisan 命令
php artisan make:provider PackagetestServiceProvider
执行完成,laravel 在 app/Providers下会生成 PackagetestServiceProvider.php 然后你把他剪切到 你的 src目录:packages/aex/packagetest/src
同时修改代码的命名空间为你刚刚定义的:namespace Aex\Packagetest;  顺便把注册服务等都写完吧,完成代码如下:
<?php
namespace Aex\Packagetest;
use Illuminate\Support\ServiceProvider;
class PackagetestServiceProvider extends ServiceProvider
{
    /**
     * 服务提供者加是否延迟加载.
     *
     * @var bool
     */
    protected $defer = true; // 延迟加载服务
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->loadViewsFrom(__DIR__ . '/views', 'Packagetest'); // 视图目录指定
        $this->publishes([
            __DIR__.'/views' => base_path('resources/views/vendor/packagetest'),  // 发布视图目录到resources 下
            __DIR__.'/config/packagetest.php' => config_path('packagetest.php'), // 发布配置文件到 laravel 的config 下
        ]);
    }
    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
         // 单例绑定服务
        $this->app->singleton('packagetest', function ($app) {
            return new Packagetest($app['session'], $app['config']);
        });
    }
    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        // 因为延迟加载 所以要定义 provides 函数 具体参考laravel 文档
        return ['packagetest'];
    }
}
自问自答:
1.为什么创建的服务要放到src 下? -- 你要开发扩展包,放到laravel下面就不算扩展包了,你的包以后要给别人用,别人会统一安装到vendor下的,总不能单独把 service 文件也打包上传吧。
同理服务定义了 publish , 配置和视图不同系统需求肯定不一样,为了让人家修改,所以我们提供发布到laravel 原始视图和配置路径的方法,总不能让人家下载了你的到 到 vendor下修改吧。
2.那么 composer.json 里的命名空间为什么修改的是laravel 根目录的? -- 啪!多嘴!哦,不对,啪啪啪啪!!! 问的好!,这个我们还没讲完嘛,后面会给他提出来的,我们需要先跑通我们的代码,再完善成可发布的
接下来注册我们的服务到 config/app.php (你使用别人家的包都需要这步的)
添加一行 Aex\Packagetest\PackagetestServiceProvider::class
下一步添加配置文件:
在 src 目录下添加 config 目录然后添加文件 packagetest.php 内容如下:
<?php
return [
    'options' => [] // 只是为了演示
];
下一步创建我们的服务真正逻辑实现的代码: 在src目录下创建文件 Packagetest.php 内容如下:
<?php
namespace Aex\Packagetest;
use Illuminate\Session\SessionManager;
use Illuminate\Config\Repository;
class Packagetest
{
    /**
     * @var SessionManager
     */
    protected $session;
    /**
     * @var Repository
     */
    protected $config;
    /**
     * Packagetest constructor.
     * @param SessionManager $session
     * @param Repository $config
     */
    public function __construct(SessionManager $session, Repository $config)
    {
        $this->session = $session;
        $this->config = $config;
    }
    /**
     * @param string $msg
     * @return string
     */
    public function test_rtn($msg = ''){
        $config_arr = $this->config->get('packagetest.options');
        return $msg.' <strong>from your custom develop package!</strong>>';
    }
}
下一步创建视图文件:在src目录下添加views目录然后添加 packagetest.blade.php
@extends('layouts.app')
@section('content')
    <h1>Packagetest Message</h1>
    {{$msg}}
@endsection
下一步创建门面(Facades): 在src目录下添加 Facades目录然后添加 Packagetest.php
<?php
namespace Aex\Packagetest\Facades;
use Illuminate\Support\Facades\Facade;
class Packagetest extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'packagetest';
    }
}
然后命令行执行 :
composer dump-autoload
这样就能够使用命名空间 Aex\Packagetest 了,上面在 config/app.php 下添加的服务那行就真正生效了。(如果不执行 dump-autoload 运行程序会报错,说找不到类)
既然我们定义了门面 那么我们就可以为这个服务添加别名了。在 config/app.php  的 aliases 数组添加一行:
'Packagetest' => Aex\Packagetest\Facades\Packagetest::class
现在我们的目录结构类似:
3
至此代码其实就已经跑通了,但是还没有完全完成。我们先测试下试试,随便找个 controller 当然 route要定义好:例如:TestController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Packagetest;
class TestController extends Controller
{
    public function test(Request $request){
        $a = Packagetest::test_rtn('Aex');
        return view('Packagetest::packagetest',['msg'=>$a]);
    }
}
然后根据路由访问就可以看到效果啦。为什么说没有完全完成呢?因为 视图文件和 config 配置文件还在我们的包里定义,以后发布出去,包会在 vendor目录下,这些文件不应该在vendor下修改
所以命令行执行:
php artisan vendor:publish --provider="Aex\Packagetest\PackagetestServiceProvider"
//  --provider 参数指定了要发布的服务 你也可以省略来发布所有的
发布后你就会在 laravel 本身的 config目录 和 views/vendor/packagetest 下看到你的文件了,也就可以按照需求随意修改了。
最后我们说 修改的laravel 的composer.json ,我们要发布我们的包,让所有人都能使用 composer 安装,那么执行如下步骤
去掉 添加的 那行 "Aex\\Packagetest\\": "packages/aex/packagetest/src/" 然后 修改 packages/aex/packagetest/composer.json
添加 autoload:
"autoload": {
    "psr-4": {
        "Aex\\Packagetest\\": "src/"
    }
}
这样包就是一个完整独立的包了,然后把他提交到你的 GitHub 上。
提交到 github 上的我的目录结构是:
4
我的地址是:https://github.com/ALawating-Rex/packagetest-for-laravel 有需要参考的可以参考下。
接着就是把包提交到 packagelist了, 网址: https://packagist.org/ 如果没有账户则注册一个
然后点击 submit ,填写项目URL,点击check
5
成功后点击  submit 就完成了。 至此你的包就可以像其它人的一样通过 composer require 安装了 6
如上图,两个箭头分别代表了包名称 和 版本
所以安装这个包的时候你的 composer.json 在require可以加这样一行:
"aex/packagetest-for-laravel": "dev-master"
安装之前我们先把我们之前开发的这个包都删除吧,就假设是一个别人的 laravel 框架要用我们的包: 删除 packages 文件夹
删除 config/packagetest.php
删除 resources/views/vendor/packagetest
conifg/app.php 里面删除添加的服务和别名
controller 里的改动就保留吧,因为安装完还是要这么写一遍 最后执行 composer dump-autoload
下面安装这个自定义包吧: composer update aex/packagetest-for-laravel
然后添加服务: 修改 config/app.php 添加
Aex\Packagetest\PackagetestServiceProvider::class
和别名的配置:
'Packagetest' => Aex\Packagetest\Facades\Packagetest::class
执行 composer dump-autoload
发布资源文件: php artisan vendor:publish --provider="Aex\Packagetest\PackagetestServiceProvider"
测试通过 大功告成!
额外的:
1.在 packagelist 你的这个包页面可以看到提示了 Set Up GitHub Service Hook 你可以按照提示办法安装,安装完成后,一旦你的项目有push,这里就会跟着更新。
2.还是 packagelist 页面,可以看到目前你只有  dev-master 版本,假设你需要其它的版本 你可以去你的 github 项目添加 tag
git tag 1.0.0 && git push --tags
这样composer require 就可以指定别的版本了。
3.为了别人能够更加清晰的使用你的包,完善你的 Readme 吧
4.不是必须laravel 框架,单纯的 composer 扩展包开发也是按照这个步骤来,只不过需要你摘出 laravel 结合的部分。

laravel blade 模版引擎指令详解和使用举例

laravel blade 模版引擎
laravel blade 模版引擎
定义片段
@section('content')
   xxxx
@show
show 表示同时显示
@section('ccc')
     xxxx
@endsection
使用 endsection 不会主动显示,只有 yield 指定的地方 和 @section ...@show 的地方会显示
显示指定片段的内容
@yield('content')
扩展布局 (继承)
// 指定子页面所继承的布局
@extend('layouts.app')
此时 这个 子页面(视图)将会使用 @section 指令注入内容到布局的片段中
子页面和父页面都有定义 @setion('content') 片段,则子页面会覆盖父页面
如果想使用追加可以使用 @parent
@section('content')
   @parent
   new - xxxx
@show
@parent指令在渲染的时将被替换为布局中的内容
注:
使用 section ... show  然后又使用了 section ... endsection (无论是在布局还是子视图中)那么show 里面的会被 endsection 定义的 覆盖
想要追加 那么要在 endsection 区添加 @parent
如果是
section ... show
section ... endsection
section ... show
那么两处show 都会被 endsection 里的内容替代。 但是要注意此时 第二个 section...show 会跑到页面的最上面,可以通过查看网页源代码发现。
 
输出 php 代码有以下方式:
1.{{ $var }}
2.{!! $var !!}
3.<?php echo $var; ?>
第三种就不用说了,第一种和第二种其实都是相当于 echo 但是第一种是 echo e($var) 调用了辅助函数e()  --> 定义:
function e($value)
{
    if ($value instanceof Htmlable) {
        return $value->toHtml();
    }
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false);
}
即有经过 html实体字符转换
第二种就是 echo $var 了  具体这些都可以参考 storage/framework/views/下编译出来的文件查看 原生内容 。
如果想让 {{}} 不被 slade 引擎转义 那么可以使用 @符号 @{{$var}} 这样就会原样输出
如果很大一块代码需要原样输出:  verbatim 指令
@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim
组件和插槽:
组件和插槽可以是 section 和 layout应用更灵活,且 也很容易理解。页面需要复用的东西可以通过 组件和插槽实现,例如:
我们在 controller 里定义要渲染的视图是 test 即 return view('test')
然后在 test.blade.php 里首先 extends('layouts.app') 然后需要引入提示消息的视图,明显这个可以在各个页面复用,那么可以使用 组件和插槽的方式:
test.blade.php:
@extends('layouts.app')
@section('content')
    <h1>test blade2</h1>
    @parent
    <hr/>
    @component('alert',['foo' => 'bar','tt'=>'TTTTHHH'])
        aaaa
        @slot('title')
            Forbidden
        @endslot
        @slot('foo')
            barbarbar
        @endslot
        @slot('aex','哈哈哈哈')
        You are not allowed to access this resource!
    @endcomponent
@endsection
alert.blade.php:
<div class="alert alert-danger">
    <div class="alert-title">{{ $title }}</div>
    {{ $slot }}
    <h1>{{$foo}}</h1>
    <h1>{!! $foo !!}</h1>
    <h2>{{$tt}}</h2>
    <h3>{{$aex}}</h3>
</div>
那么由此 上面的 section 会被放到 layouts.app 里 yield 定义的content 这些都是之前的概念了。
componet 定义了 alert 于是就会去渲染 alert.blade.php 后面的数组可以不定义,定义了就是往alert视图注入变量 即:$foo = 'bar', $tt = 'TTTTHHH' 这样就可以做到把 controller里的变量传递给 alert视图了
后面的 @slot 指令其实也是相当于 $title = 'Forbidden'
还可以写为 @slot('aex','哈哈哈哈')  即 $aex = '哈哈哈哈';
最后你会发现还有不再 @slot指令里的内容 即 aaaa 和 You are not allowed to access this resource! 他们会被放到 alert 模版 $slot 指定的地方。
感兴趣的仍然可以去看下 framework 编译的原始文件 ,大致会看到 $__env->startComponent('alert',['foo' => 'bar','tt'=>'TTTTHHH']) ... 这样的内容,
然后看下 startComponent 的定义以及其它的函数定义 就大致理解工作流程了(主要使用了 ob_start 和 ob_get_clean 等)。 定义文件在:\vendor\laravel\framework\src\Illuminate\View\Concerns\ManagesComponents.php
子视图:
Blade 的 @include 指令允许你很轻松地在一个视图中包含另一个 Blade 视图,所有父级视图中变量在被包含的子视图中依然有效:
<div>
    @include('shared.errors')
    <form>
        <!-- Form Contents -->
    </form>
</div>
尽管被包含的视图可以继承所有父视图中的数据,你还可以传递额外参数到被包含的视图:
@include('view.name', ['some' => 'data'])
堆栈:
前端页面  js我们通常希望放到页脚,不同页面引入的 js 又不一样,想要做到这点就可以使用堆栈功能。
例如在布局文件 app.blade.php 最下面 </body> 上面加入 @stack('scripts') 然后在你要渲染的视图 例如 test.blade.php 将js推送入栈即可
@push('scripts')
    <script type="text/javascript" src="/jquery.min.js"></script>
@endpush
服务注入:
视图中大部分变量是通过 controller 传递的,但是有的时候我们仍需要调用 laravel 的一些类获取相应的值,那么可以使用 @inject 指令
@inject 指令可以用于从服务容器中获取服务,传递给 @inject 的第一个参数是服务将要被分配到的变量名,第二个参数是要解析的服务类名或接口名:
@inject('metrics', 'App\Services\MetricsService')
<div>
    Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>
你也可以这样使用:
<?php
    var_dump(App\User::where('id',1)->first()->toArray());
?>

laravel 框架以及关键概念重新理解

laravel 重新理解
首先 laravel 核心就是一个 Ioc (依赖注入 )容器。框架本身需要的很多东西其实就是各个服务,每一个服务的实现我们可以称为服务容器。
服务举例,有auth 认证服务、cache缓存服务、DB数据库服务、fileSystem文件系统服务 等等,当然你也可以自己添加第三方的 excel 服务 zip服务等。
有了各种各样的服务来实现我们的需求,那么如何使用这些服务呢?即服务的绑定和解析。
首先服务需要被绑定,类似变量赋值一样,我们使用这个变量就相当于用这个值,那么服务绑定到某个名称上,例如:

$this->app->singleton('cache', function ($app) {
return new CacheManager($app);
});

这样当我们通过某种方式调用 cache这个名称 的时候就相当于调用了 cache 服务。cache 服务的实现主要就是 上述代码 CacheManager 中实现的。
服务绑定的方式:
简单绑定:
$this->app->bind('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app->make('HttpClient'));
});
第一个参数是想要注册的类名或者接口名,第二个参数是返回类的实例的闭包。
绑定一个单例:
singleton 方法绑定一个只需要解析一次的类或接口到容器,然后接下来对容器的调用将会返回同一个实例:
$this->app->singleton('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app->make('HttpClient'));
});
绑定实例 :
你还可以使用 instance 方法绑定一个已存在的对象实例到容器,随后调用容器将总是返回给定的实例:
$api = new HelpSpot\API(new HttpClient);
$this->app->instance('HelpSpot\Api', $api);
绑定原始值 :
你可能有一个接收注入类的类,同时需要注入一个原生的数值比如整型,可以结合上下文轻松注入这个类需要的任何值:
$this->app->when('App\Http\Controllers\UserController')
    ->needs('$variableName')
    ->give($value);
类似的还有上下文绑定
有时侯我们可能有两个类使用同一个接口,但我们希望在每个类中注入不同实现,
例如,两个控制器依赖 Illuminate\Contracts\Filesystem\Filesystem 契约的不同实现。
Laravel 为此定义了简单、平滑的接口:
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\VideoController;
use App\Http\Controllers\PhotoControllers;
use Illuminate\Contracts\Filesystem\Filesystem;
$this->app->when(PhotoController::class)
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('local');
    });
$this->app->when(VideoController::class)
    ->needs(Filesystem::class)
    ->give(function () {
        return Storage::disk('s3');
    });
绑定接口到实现
服务容器的一个非常强大的功能是其绑定接口到实现。我们假设有一个 EventPusher 接口及其实现类RedisEventPusher ,
编写完该接口的 RedisEventPusher 实现后,就可以将其注册到服务容器:
$this->app->bind(
    'App\Contracts\EventPusher',
    'App\Services\RedisEventPusher'
);
这段代码告诉容器当一个类需要 EventPusher 的实现时将会注入 RedisEventPusher,
现在我们可以在构造器或者任何其它通过服务容器注入依赖的地方进行 EventPusher 接口的依赖注入:
use App\Contracts\EventPusher;
/**
 * 创建一个新的类实例
 *
 * @param  EventPusher  $pusher
 * @return void
 */
public function __construct(EventPusher $pusher){
    $this->pusher = $pusher;
}
绑定有了 ,接下来就是考虑怎么使用的问题了。即 解析:
make方法 :
有很多方式可以从容器中解析对象,首先,你可以使用 make 方法,该方法接收你想要解析的类名或接口名作为参数:
$fooBar = $this->app->make('HelpSpot\API');
如果你所在的代码位置访问不了 $app 变量,可以使用辅助函数resolve
$api = resolve('HelpSpot\API');
自动注入 :
最后,也是最常用的,你可以简单的通过在类的构造函数中对依赖进行类型提示来从容器中解析对象,
控制器、事件监听器、队列任务、中间件等都是通过这种方式。在实践中,这是大多数对象从容器中解析的方式。
容器会自动为其解析类注入依赖,例如,你可以在控制器的构造函数中为应用定义的仓库进行类型提示,该仓库会自动解析并注入该类:
<?php
namespace App\Http\Controllers;
use App\Users\Repository as UserRepository;
class UserController extends Controller{
    /**
     * 用户仓库实例
     */
    protected $users;
    /**
     * 创建一个控制器实例
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}
至此服务的使用也就理清楚了。回过头来,再考虑我们说了服务绑定,但是细致的说 还要讲明白绑定声明在哪里。
也就是概念:服务提供者  (serviceProvider) 所有的的 laravel 服务都是通过服务提供者启动的。
即所有的服务都继承自 Illuminate\Support\ServiceProvider 类。大部分服务提供者都包含两个方法: register 和 boot 。
在 register 方法中,你唯一要做的事情就是绑事物到服务容器,不要尝试在其中注册事件监听器,路由或者任何其它功能。
通过 Artisan 命令 make:provider 即可生成一个新的提供者:
php artisan make:provider RiakServiceProvider
register方法
正如前面所提到的,在 register 方法中只绑定事物到服务容器,而不要做其他事情,否则,一不小心就能用到一个尚未被加载的服务提供者提供的服务。
现在让我们来看看一个基本的服务提供者长什么样:
<?php
namespace App\Providers;
use Riak\Connection;
use Illuminate\Support\ServiceProvider;
class RiakServiceProvider extends ServiceProvider{
    /**
     * 在容器中注册绑定.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection(config('riak'));
        });
    }
}
该服务提供者只定义了一个 register 方法,并使用该方法在服务容器中定义了一个 Riak\Contracts\Connection 的实现。
boot方法
如果我们想要在服务提供者中注册视图 composer 该怎么做?这就要用到 boot 方法了。
该方法在所有服务提供者被注册以后才会被调用,这就是说我们可以在其中访问框架已注册的所有其它服务:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        view()->composer('view', function () {
            //
        });
    }
}
我们也可以在boot方法中类型提示依赖
use Illuminate\Contracts\Routing\ResponseFactory;
public function boot(ResponseFactory $response){
    $response->macro('caps', function ($value) {
        //
    });
}
这样服务提供者有了,服务就能顺利的被调用了。再接着往回想,那么服务提供者又是怎么注册声明的呢?
即:注册服务提供者
所有服务提供者都是通过配置文件 config/app.php 中进行注册,该文件包含了一个列出所有服务提供者名字的 providers 数组,
默认情况下,其中列出了所有核心服务提供者,这些服务提供者启动 Laravel核心组件,比如邮件、队列、缓存等等。
要注册你自己的服务提供者,只需要将其追加到该数组中即可:
'providers' => [
    // 其它服务提供者
    App\Providers\ComposerServiceProvider::class,
],
注: 在这里声明的服务,laravel在启动的时候会自动的运行所有服务提供者的内容。
延迟加载服务提供者
框架启动的时候只启动必要的服务,其它不必要的服务在用的时候启动这就是延迟加载服务提供者,这才是合理的或者说好的启动方案。
想要延迟加载一个提供者,设置 defer 属性为 true 并定义一个 provides 方法,该方法返回该提供者注册的服务容器绑定,
可以自行参考 RedisServiceProvider (声明 defer 以及 注册了多个服务绑定)
终于一个完整的服务提供,注册,绑定,解析流程完成了。
接下来为了使服务的调用更加简单,Laravel 使用了 Facades(门面)
门面:
门面为应用服务容器中的绑定类提供了一个“静态”接口。我们完全可以只使用服务,例如
$value = resolve('cache')->get('key'); // laravel 要解析 cache ,通过服务提供者列表找到 cache 的服务提供者 进而找到 服务绑定 的类实现,然后最终调用其 get方法
但是有了门面,我们调用起来就更加简单明了
use cache;
$value = cache::get('key');
上面的例子,内部工作流程实际上是:
laravel 在 config/app.php 里面声明的别名 aliases 找到 cache对应的门面类: Illuminate\Support\Facades\Cache::class
这个里面主要声明了方法:getFacadeAccessor   返回 cache  这次这个cache对应的就是服务容器绑定的名称了,
服务提供者会在启动的时候绑定 cache 对应的类实现,那么laravel自然就找到了对应的实现,进而调用其 get方法。
而对开发来说表面看起来就像是直接调用 cache这个类的 get静态方法一样,语义明确。
其实浏览门面的基类代码,Facade 就会发现魔术方法 __calStatic() 这里去调用指定的方法。
契约:
Laravel 中的契约是指框架提供的一系列定义核心服务的接口,Contracts(契约)使得实现更加的松耦合和简单
举例看一个紧耦合代码:
<?php
namespace App\Orders;
class Repository
{
    protected $cache;
    /**
     * 创建一个新的Repository实例
     *
     * @param  \SomePackage\Cache\Memcached  $cache
     * @return void
     */
    public function __construct(\SomePackage\Cache\Memcached $cache)
    {
        $this->cache = $cache;
    }
    /**
     * 通过ID获取订单
     *
     * @param  int  $id
     * @return Order
     */
    public function find($id)
    {
        if ($this->cache->has($id))    {
            //
        }
    }
}
在类初始化的时候自动注入 \SomePackage\Cache\Memcached 类对象,但是如果下次想换成 redis 等,就不得不来这里修改 注入的类。
那么如果使用契约呢:
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class Repository
{
    /**
     * 创建一个新的Repository实例
     *
     * @param  Cache  $cache
     * @return void
     */
    public function __construct(Cache $cache)
    {
        $this->cache = $cache;
    }
}
松耦合:
无论 cache 怎么变,实现处不用修改代码,所以降低了耦合性。
简单:
当所有 Laravel 服务都统一在简单接口中定义,很容易判断给定服务提供的功能。契约可以充当框架特性的简明文档
契约的使用:
Laravel中很多类都是通过服务容器进行解析,包括控制器,以及监听器、中间件、队列任务,甚至路由闭包。所以,要实现一个契约,需要在解析类的构造函数中类型提示这个契约接口。
契约和门面不同之处:
从使用上的不同,我们在使用门面的时候都是主动 声明 哪个门面,然后调用其"静态"方法,
而门面更多的是声明到类的构造函数中,系统会自动注入,接着就可以使用了。
契约允许你在类中定义显示的依赖,这样更加明确。

 

 

Magento 手机支付 (支付宝无线支付)

 现在magento 支付宝插件在网上还是很多的。但是支付宝无线支付貌似还不多。这里我只是根据官方文档和其它

支付方式编写出无线支付的雏形,可用但是不完善,先记录在这里。(当然文章是点到为止,只给我这种菜鸟看看,大神无视我吧。)

---------------------------------------------------我就是分割线怎么了---------------------------------------------------

首先肯定是要熟悉支付宝官方给出的文档

手机网页即时到账接口 和 手机网页支付接入与使用规则 以及 demo 代码

之后开始梳理流程:

(一下是在默认情况下,不要纠结个别变量的不同)

1. 在magento中我们点击结账,如果支付方式选择的是第三方支付方式会跳转到相应支付方式Paymentcontroller里的redirectAction

在模块的system.xml 中加入你自己的后台配置代码

2. 在这里magento最主要的是 记录$order以及createBlock 输出html

$this->getResponse()
            ->setBody($this->getLayout()
                ->createBlock('alipaymobile/redirect')
                ->setOrder($order)
                ->toHtml());

3. 在输出的页面 例如是支付宝或者快钱等支付方式通常是隐藏的form表单包含要提交的信息,以及自动提交的js

但是支付宝无线支付有些不同,从官方文档中得知 我们首先需要 获得授权即调用接口手机网页即时到账授权接口

然后才是 调用接口手机网页即时到账交易接口

那么我的解决思路是在 Block/Redirect.php 中先去掉用授权接口然后是代码自动调用即时到帐接口完成结账。

这时候看到的网页是要跳转两次的。

4. 首先调用授权接口 隐藏的form表单提交的 url地址应当是 里一个例如AlipayapiController

并且主要代码都是在这个controller中实现的

//建立请求
        $alipaySubmit = new AlipaySubmit($alipay_config);
        $html_text = $alipaySubmit->buildRequestHttp($para_token);

 

//获取request_token
        $request_token = $para_html_text['request_token'];

 

//建立请求
        $alipaySubmit = new AlipaySubmit($alipay_config);
        $html_text = $alipaySubmit->buildRequestForm($parameter, 'get', '确认');

注意:按这种方法其中出现的一个重要问题是会获取不到 notifyUrl 和 SuccessUrl, (除非你直接写的绝对路径,而不是从model中获取的)

是因为 在model中 getSuccessURL 和 getNotifyURL 都是使用protected声明的。 最简单的解决办法是改成public

以我之愚见好像没必要声明成protected

5. 处理success代码 和 notify代码即可。

 

 

 

 

这完成了结账流程没错,但是只是90%吧,因为还有重要的前端处理流程。

即PC端 是不需要显示这个支付方式的 一种解决办法是

在template/checkout/onpage/payment/methods.phtml 中找到代码

foreach ($methods as $_method):
        $_code = $_method->getCode();

在后面加上

if($_code == "alipaymobile_payment"){
            continue;
        }

即可,当然这里的 alipaymobile_payment  要自己根据实际情况来定了。

另一个需要修改的地方是我的订单包括历史订单页面(我这里实在之前开发了继续支付功能)

当你在手机选择了 支付宝无线支付 但是没有做付款操作,转而用电脑继续,那么此时在订单付款按钮处就

不应该选择支付宝无线支付了。可以使用

$paymentsAllMethods = Mage::getSingleton('payment/config')->getActiveMethods();

过滤出可用的支付方式即可。

至此 就基本完成了。大家凑合看吧,其实有了官方文档,加上对magento有些了解花点时间就可以写出来的

我只不过写下我自己的解决办法。 不喜勿喷!欢迎指正!

 

懒得开发的可以联系我

但我不会去帮你定制。(哎呀,我的服务竟然这么差!)

 

---------------------------------------------------我就是分割线怎么了---------------------------------------------------

这是发在CSDN的第一篇文章,所以必须是原创的!

最开始在新浪上写博客,后来到百度空间,我只想说百度空间让我几乎没有了写博客的欲望。

总之现在又想乱写点东西了,给自己看也好。

PS: 会陆续把我印象笔记里的东西拿过来。

 

 

此文章通过 python 爬虫创建,原文是自己的csdn 地址: Magento 手机支付 (支付宝无线支付)