Skip to content

Commit

Permalink
Adds tests and readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan Hoff committed Apr 24, 2017
1 parent 2c90342 commit 23a28f0
Show file tree
Hide file tree
Showing 9 changed files with 479 additions and 6 deletions.
148 changes: 148 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
Laravel Blade Vue Directive
==============

Laravel Blade Vue Directive provides a blade directive for vue.js inline components.

[![Latest Stable Version](https://img.shields.io/github/release/jhoff/blade-vue-directive.svg?style=flat-square)](https://packagist.org/packages/jhoff/blade-vue-directive)
[![Total Downloads](https://img.shields.io/packagist/dt/jhoff/blade-vue-directive.svg?style=flat-square)](https://packagist.org/packages/jhoff/blade-vue-directive)
[![MIT License](https://img.shields.io/packagist/l/jhoff/blade-vue-directive.svg?style=flat-square)](https://packagist.org/packages/jhoff/blade-vue-directive)
[![Build Status](https://scrutinizer-ci.com/g/jhoff/blade-vue-directive/badges/build.png?b=master)](https://scrutinizer-ci.com/g/jhoff/blade-vue-directive/build-status/master)
[![Code Coverage](https://scrutinizer-ci.com/g/jhoff/blade-vue-directive/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/jhoff/blade-vue-directive/?branch=master)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/jhoff/blade-vue-directive/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/jhoff/blade-vue-directive/?branch=master)

<!-- MarkdownTOC autolink="true" autoanchor="true" bracket="round" depth="4" -->

- [Installation](#installation)
- [Usage](#usage)
- [Basic Example](#basic-example)
- [Scalars Example](#scalars-example)
- [Booleans and Numbers Example](#booleans-and-numbers-example)
- [Objects and Arrays Example](#objects-and-arrays-example)

<!-- /MarkdownTOC -->

<a name="installation"></a>
## Installation

To install the Laravel Blade Vue Directive, simply run `composer require blade-vue-directive` in a terminal, or if you prefer to manually install you can the following in your `composer.json` file and then run `composer install` from the terminal:

```json
{
"require": {
"jhoff/blade-vue-directive": "1.*"
}
}
```

Then all you need to do is add the new provider to the providers array of `config/app.php`:

```php
'providers' => [
// ...
Jhoff\BladeVue\DirectiveServiceProvider::class,
// ...
],
```

<a name="usage"></a>
## Usage

The Laravel Blade Vue Directive was written to be simple and intuitive to use. It's not opinionated about how you use your vue.js components. Simply provide a component name and (optionally) an associative array of properties.

<a name="basic-example"></a>
### Basic Example

Using the vue directive with no arguments in your blade file

```html
@vue('my-component')
<div>Some content</div>
@endvue
```

Renders in html as

```html
<component inline-template v-cloak is="my-component">
<div>Some content</div>
</component>
```

<a name="scalars-example"></a>
### Scalars Example

Using the vue directive with an associative array as the second argument will automatically translate into native properties that you can use within your vue.js components.

```html
@vue('page-title', ['title' => 'Welcome to my page'])
<h1>@{{ title }}</h1>
@endvue
```

Renders in html as

```html
<component inline-template v-cloak is="page-title" title="Welcome to my page">
<h1>{{ title }}</h1>
</component>
```

Then, to use the properties in your vue.js component, add them to `props` in your component definition. See [Component::props](https://vuejs.org/v2/guide/components.html#Props) for more information.

```js
Vue.component('page-title', {
props: ['title']
});
```

<a name="booleans-and-numbers-example"></a>
### Booleans and Numbers Example

Properties that are booleans or numeric will be bound automatically as well

```html
@vue('report-viewer', ['show' => true, 'report' => 8675309])
<h1 v-if="show">Report #@{{ report }}</h1>
@endvue
```

Renders in html as

```html
<component inline-template v-cloak is="report-viewer" :show="true" :report="8675309">
<h1 v-if="show">Report #{{ report }}</h1>
</component>
```

<a name="objects-and-arrays-example"></a>
### Objects and Arrays Example

The vue directive will automatically handle any objects or arrays to make sure that vue.js can interact with them without any additional effort.

```html
@vue('welcome-header', ['user' => (object)['name' => 'Jordan Hoff']])
<h2>Welcome @{{ user.name }}!</h2>
@endvue
```

Renders in html as

```html
<component inline-template v-cloak is="welcome-header" :user="{&quot;name&quot;:&quot;Jordan Hoff&quot;}">
<h2>Welcome {{ user.name }}!</h2>
</component>
```

Notice that the object is json encoded, html escaped and the property is prepended with `:` to ensure that vue will bind the value as data.

To use an object property in your component, make sure to make it an `Object` type:

```js
Vue.component('welcome-header', {
props: {
user: {
type: Object
}
}
});
```
43 changes: 43 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="false"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Integration Tests">
<directory suffix="Test.php">tests/Integration</directory>
</testsuite>
<testsuite name="Unit Tests">
<directory suffix="Test.php">tests/Unit</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-html"
target="coverage"
lowUpperBound="35"
highLowerBound="70"/>
<log type="coverage-clover"
target="coverage/clover.xml"/>
<log type="coverage-text"
target="php://stdout"
showOnlySummary="true"/>
</logging>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
</php>
</phpunit>
4 changes: 4 additions & 0 deletions src/Component.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ protected function resolveAttributeValue(string $name, $value) : array
return [":$name", $value ? 'true' : 'false'];
}

if (is_numeric($value)) {
return [":$name", $value];
}

if (!is_scalar($value) && !is_null($value)) {
return [":$name", htmlspecialchars(json_encode($value), ENT_QUOTES, 'UTF-8', false)];
}
Expand Down
22 changes: 16 additions & 6 deletions src/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ public function getEndTag() : string
*/
public function getStartTag() : string
{
return "<{$this->name} {$this->renderAttributes()}>";
$attributes = $this->renderAttributes();

return "<{$this->name}" . ( $attributes ? ' ' . $attributes : '' ) . '>';
}

/**
Expand All @@ -62,6 +64,18 @@ public function setAttribute(string $name, $value)
return $this;
}

/**
* Builds an attribute string
*
* @param string $key
* @param mixed $value
* @return string
*/
protected function buildAttribute(string $key, $value) : string
{
return is_null($value) ? $key : sprintf('%s="%s"', $key, $value);
}

/**
* Renders all of the attributes in the proper format
*
Expand All @@ -70,11 +84,7 @@ public function setAttribute(string $name, $value)
protected function renderAttributes() : string
{
return implode(' ', array_map(
function ($key, $value) {
return is_null($value) ?
sprintf("%s", $key) :
sprintf("%s=\"%s\"", $key, $value);
},
[$this, 'buildAttribute'],
array_keys($this->attributes),
$this->attributes
));
Expand Down
49 changes: 49 additions & 0 deletions tests/Integration/BladeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Jhoff\BladeVue\Testing\Integration;

use Jhoff\BladeVue\Testing\TestCase;

class BladeTest extends TestCase
{
/**
* @test
*/
public function bladeRendersBasicVueDirective()
{
$output = $this->renderBlade('"my-component"');

$this->assertContains('<component', $output);
$this->assertContains('is="my-component"', $output);
$this->assertContains('</component>', $output);
}

/**
* @test
*/
public function bladeRendersAdvancedVueDirective()
{
$output = $this->renderBlade('"my-component", ["foo" => "bar"]');

$this->assertContains('<component', $output);
$this->assertContains('is="my-component"', $output);
$this->assertContains('foo="bar"', $output);
$this->assertContains('</component>', $output);
}

/**
* Creates a vue file in the testbench views directory and renders it
*
* @param string $expression
* @return string
*/
protected function renderBlade(string $expression)
{
@file_put_contents(
resource_path('views/vue.blade.php'),
"@vue($expression)\n<div>Testing</div>\n@endvue"
);

return view()->make('vue')->render();
}
}
19 changes: 19 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Jhoff\BladeVue\Testing;

use Orchestra\Testbench\TestCase as BaseTestCase;

class TestCase extends BaseTestCase
{
/**
* Get package providers.
*
* @param \Illuminate\Foundation\Application $app
* @return array
*/
protected function getPackageProviders($app)
{
return ['Jhoff\BladeVue\DirectiveServiceProvider'];
}
}
Loading

0 comments on commit 23a28f0

Please sign in to comment.