twig使用变量_使用Laravel合约构建Laravel 5 Twig软件包

twig使用变量

Laravel 5 is finally out, and with all the awesome features it brings. One of the new architectural changes is the new Contracts Package. In this article we are going to understand the reasoning behind this change and try to build a practical use case using the new Contracts.

Laravel 5终于面世了,它具有所有令人敬畏的功能。 新的体系结构更改之一是新的Contracts Package 。 在本文中,我们将了解此更改背后的原因,并尝试使用新的Contract构建实际的用例。

Laravel

什么是合约 (What Is a Contract)

A contract is an interface that defines a behaviour. Let’s take this definition from Wikipedia.

合同是定义行为的接口。 让我们从Wikipedia中获得这个定义。

In object-oriented languages, the term interface is often used to define an abstract type that contains no data or code, but defines behaviors as method signatures.

在面向对象的语言中,术语“接口”通常用于定义不包含数据或代码但将行为定义为方法签名的抽象类型。

With that being said, we use interfaces to extract the object behaviour from a class to an interface and only depend upon the definition. In Laravel’s IoC container you can bind an interface to an implementation.

话虽如此,我们使用接口将对象行为从类提取到接口,并且仅依赖于定义。 在Laravel的IoC容器中,您可以将接口绑定到实现

$this->app->bind('App\Contracts\EventPusher', 'App\Services\PusherEventPusher');

Now every time you resolve the EventPusher interface from the container, you will receive a Pusher implementation. If you decide to switch to another service like Fanout, you only need to change the binding.

现在,每次您从容器中解析EventPusher接口时,您都会收到一个Pusher实现。 如果您决定切换到另一服务,例如Fanout ,则只需更改绑定。

$this->app->bind('App\Contracts\EventPusher', 'App\Services\FanoutEventPusher');

Most of Laravel core services now are extracted to a contract, and if you want for example to override the Illuminate/Mail service, you can implement the Illuminate\Contracts\Mail contract and define the necessary methods and add it a s a provider.

现在,大多数Laravel核心服务都已提取到合同中,并且,例如,如果您要覆盖Illuminate/Mail服务,则可以实现Illuminate\Contracts\Mail合同并定义必要的方法并将其添加为提供者。

Laravel查看合同 (Laravel View Contract)

Laravel uses its own template engine called Blade. However, I want to use Symfony Twig as my template engine. Blade already offers the possibility to register your own extensions; check the Twig Bridge for more info. Laravel 5 has a better way to achieve the same goal using Contracts, so let’s create our own implementation.

Laravel使用自己的模板引擎Blade 。 但是,我想使用Symfony Twig作为模板引擎。 Blade已经提供了注册您自己的扩展的可能性。 查看Twig Bridge以获取更多信息。 Laravel 5有一个更好的方法来使用Contracts实现相同的目标,因此让我们创建自己的实现。

定义包装 (Defining The Package)

To start building our package, we need to define it inside the composer.json file. We require Twig and autoload our src folder as our root namespace.

要开始构建我们的包,我们需要在composer.json文件中定义它。 我们需要Twig并自动加载src文件夹作为我们的根名称空间。

// composer.json
{
  "name": "whyounes/laravel5-twig",
  "description": "Twig for Laravel 5",
  "authors": [
    {
      "name": "RAFIE Younes",
      "email": "younes.rafie@gmail.com"
    }
  ],
  "require": {
    "twig/twig": "1.18.*"
  },
  "autoload": {
    "psr-0": {
      "RAFIE\\": "src/"
    }
  }
}

查看服务提供商 (View Service Provider)

The preferable way to register your package bindings is through a Service Provider.

注册软件包绑定的首选方法是通过服务提供商

// src/RAFIE/Twig/TwigViewServiceProvider.php

public function registerLoader()
{
  $this->app->singleton('twig.loader', function ($app) {
    $view_paths = $app['config']['view.paths'];
    $loader = new \Twig_Loader_Filesystem($view_paths);

    return $loader;
  });
}

The registerLoader method will bind our Twig Loader to the container. The $app['config']['view.paths'] contains our view paths. By default, it has only the resources/views folder.

registerLoader方法会将Twig Loader绑定到容器。 $app['config']['view.paths']包含我们的视图路径。 默认情况下,它仅具有resources/views文件夹。

// src/RAFIE/Twig/TwigViewServiceProvider.php

public function registerTwig()
{
  $this->app->singleton('twig', function ($app) {
    $options = [
        'debug' => $app['config']['app.debug'],
        'cache' => $app['config']['view.compiled'],
    ];

    $twig = new \Twig_Environment($app['twig.loader'], $options);

    // register Twig Extensions
    $twig->addExtension(new \Twig_Extension_Debug());

    // register Twig globals
    $twig->addGlobal('app', $app);

    return $twig;
  });
}

The Twig_Environment class is the Twig core class. It accepts a Twig_LoaderInterface and a list of options:

Twig_Environment类是Twig核心类。 它接受Twig_LoaderInterface和选项列表:

  • $app['config']['app.debug'] retrieves our debug flag from the config file.

    $app['config']['app.debug']从配置文件中检索我们的调试标志。

  • $app['config']['view.compiled'] is our compiled views path registered inside the config/view.php file.

    $app['config']['view.compiled']是我们在config/view.php文件中注册的已编译视图路径。

The $twig->addGlobal method registers a variable to be available for all views.

$twig->addGlobal方法注册一个变量,以供所有视图使用。

// src/RAFIE/Twig/TwigViewServiceProvider.php

namespace RAFIE\Twig;

class TwigViewServiceProvider extends ServiceProvider
{
	public function register()
	{
	   $this->registerLoader();
	   $this->registerTwig();
	
	   $this->app->bind('view', function ($app) {
	     return new TwigFactory($app);
	   });
	 }
}

The register method will bind the twig and twig.loader to the container. The view key was previously holding the Blade view factory, now it will resolve our new TwigFactory class which will be responsible for rendering our view. Laravel won’t load your service provider by default, so you need to register it inside your config/app.php providers array. We will also comment out the Laravel view service provider.

register的方法将结合twigtwig.loader到容器上。 view键以前是保存Blade视图工厂的,现在它将解析新的TwigFactory类,该类将负责渲染视图。 Laravel默认不会加载您的服务提供商,因此您需要在config/app.php provider数组中注册它。 我们还将注释掉Laravel视图服务提供者。

// config/app.php

...
'providers' => [
	'RAFIE\Twig\TwigViewServiceProvider',
	//'Illuminate\View\ViewServiceProvider',
...

查看工厂 (View Factory)

The TwigFactory class must implement the Illuminate\Contracts\View\Factory interface to get the shape and behaviour of the view system. This class will do the job of passing the view to the Twig parser. To achieve more loose coupling, we have a TwigView class which implements the Illuminate\Contracts\View\View contract. This class will behave as a bag for the view object, and will have a reference to the TwigFactory class.

TwigFactory类必须实现Illuminate\Contracts\View\Factory接口才能获取视图系统的形状和行为。 此类将完成将视图传递给Twig解析器的工作。 为了实现更宽松的耦合,我们有一个TwigView类,该类实现了Illuminate\Contracts\View\View合同。 此类将充当视图对象的包,并且将引用TwigFactory类。

// src/RAFIE/Twig/TwigFactory.php

class TwigFactory implements FactoryContract
{

  /*
   * Twig environment
   *
   * @var Twig_Environment
   * */
  private $twig;

  public function __construct(Application $app)
  {
    $this->twig = $app['twig'];
  }

  public function exists($view)
  {
    return $this->twig->getLoader()->exists($view);
  }

  public function file($path, $data = [], $mergeData = [])
  {
    // or maybe use the String loader
    if (!file_exists($path)) {
      return false;
    }

    $filePath = dirname($path);
    $fileName = basename($path);

    $this->twig->getLoader()->addPath($filePath);

    return new TwigView($this, $fileName, $data);
  }

  public function make($view, $data = [], $mergeData = [])
  {
    $data = array_merge($mergeData, $data);

    return new TwigView($this, $view, $data);
  }

  public function share($key, $value = null)
  {
    $this->twig->addGlobal($key, $value);
  }

  public function render($view, $data)
  {
    return $this->twig->render($view, $data);
  }
	
  public function composer($views, $callback, $priority = null){}

  public function creator($views, $callback){}
  
  public function addNamespace($namespace, $hints){}

}

We resolve the twig object from the container with the parameters explained previously and we start implementing method’s logic. I omitted the last three functions, because defining them will involve creating events and dispatching them, and will make our simple example more complex. The make method returns a new TwigView instance with the current factory, view, and data.

我们使用前面解释的参数从容器中解析出twig对象,然后开始实现方法的逻辑。 我省略了最后三个函数,因为定义它们将涉及创建事件和调度它们,并使我们的简单示例更加复杂。 make方法返回具有当前工厂,视图和数据的新TwigView实例。

// src/RAFIE/Twig/TwigView.php

use Illuminate\Contracts\View\View as ViewContract;

class TwigView implements ViewContract
{
  /*
   * View name to render
   * @var string
   * */
  private $view;

  /*
   * Data to pass to the view
   * @var array
   * */
  private $data;

  /*
   * Twig factory
   * @var RAFIE\Twig\TwigFactory
   * */
  private $factory;


  public function __construct(TwigFactory $factory, $view, $data = [])
  {
    $this->factory = $factory;
    $this->view = $view;
    $this->data = $data;
  }
  
  public function render()
  {
    return $this->factory->render($this->view, $this->data);
  }

  public function name()
  {
    return $this->view;
  }

  public function with($key, $value = null)
  {
    $this->data[$key] = $value;

    return $this;
  }
  
  public function __toString()
  {
    return $this->render();
  }
}

Let’s take a normal scenario where we have our index page route that returns a home view, and we also provide a variable that ensures our data is passed to the view.

让我们以一个正常的场景为例,在该场景中,我们的索引页面路由返回了主视图,并且还提供了一个变量,以确保将数据传递到该视图。

// app/Http/routes.php

Route::get('/', function(){
	return View::make('home.twig', ['name' => 'younes']);
});

// we can also pass the name by chaining the call to the `with` method.
Route::get('/', function(){
	return View::make('home.twig')->with('name', 'younes');
});
// resources/views/home.twig

 <h2>Hello {{ name|upper }}</h2>
Home

When you hit your application’s index page, the execution flow will be:

当您点击应用程序的索引页时,执行流程将是:

  • The View facade will be resolved from the container and return a TwigFactory instance.

    View外观将从容器中解析出来,并返回TwigFactory实例。

  • The make method is called and it returns a new TwigView instance with the factory, view and data.

    调用make方法,它将返回带有工厂,视图和数据的新TwigView实例。

  • Laravel Router accepts a Response object or a string as a request response, so the __toString method is called on our TwigView instance. The render method inside the TwigFactory calls the render method on the Twig_Environment object.

    Laravel Router接受Response对象或字符串作为请求响应,因此在我们的TwigView实例上调用__toString方法。 该render的内部方法TwigFactory调用render on方法Twig_Environment对象。

When using contracts, the application API is always consistent, so testing the other implemented methods will be done the same way as before.

使用合同时,应用程序API始终是一致的,因此将以与以前相同的方式测试其他实现的方法。

// test if a view exists
View::exists('contact.twig');

// render a view from a different folder
View::file('app/contact.twig');

结论 (Conclusion)

Check out the final version of the project here.

此处签出项目的最终版本。

The new Contracts package provides a better way to extend Laravel core components, and provides a stable API for developers to access the framework’s behaviour. Let me know what you think about the new Contracts package in the comments, and if you have any questions don’t hesitate to post them below.

新的Contracts包提供了扩展Laravel核心组件的更好方法,并为开发人员提供了访问框架行为的稳定API。 让我知道您在评论中对新合同包的想法,如果有任何疑问,请随时在下面发布。

翻译自: https://www.sitepoint.com/use-laravel-contracts-build-laravel-5-twig-package/

twig使用变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值