GithubHelp home page GithubHelp logo

php-vuejs's Introduction

PHP-VueJS

Scrutinizer Code Quality Code Coverage Build Status Code Intelligence Status
VueJS integration for PHP frameworks PHP-VueJS adds VueJS to any PHP projects, it could be native, or even PHP Framework projects

๐Ÿ“ Get started

The recommended way to use this library is using Composer, run this command from the directory where is located composer.json

composer require phpmv/php-vuejs

๐Ÿ“• Guide

Creation of Vue Manager

It manages the whole script injected , you must instantiate it

$vueManager = VueManager::getInstance();

VueManager methods

Creation of Vue object

$vue = new VueJs();

VueJS arguments

  1. (associative array) configuration = ["el" => "#app"] [optionnal]
  2. (string) variable name = "app" [optionnal]
  3. (boolean) enable vuetify = false [optionnal]

VueJS methods

Creation of Component Object

$component = new VueJSComponent('component-one');

VueJSComponent argument's

  1. (string) name
  2. (string) variable name = null [optionnal]

Component name must respect kebab-case principle, if you don't provide a variable name, it would be name converted to PascalCase

VueJSComponent methods

Object Data

$object->addData('name',true);
$object->addDataRaw('name','true');

addData, addDataRaw arguments

  1. (string) name
  2. (string) value

These two lines of code generate exactly the same Vue data

data: { "name": true }

Object Methods

$object->addMethod('greet','window.alert(`Hello ${name}`);',['name']);

addMethod arguments

  1. (string) name
  2. (string) function's body
  3. (array) function's argument(s) [optionnal]

This will generate the content below

methods: {
	"greet":
		function(name){
			window.alert(`Hello ${name}`);
		}
}

Object Computeds

$object->addComputed('reversedMessage',"return this.message.split('').reverse().join('');");

addComputed arguments

  1. (string) name
  2. (string) get function's body
  3. (string) set function's body by default the function argument is v [optionnal]

This will generate the content below

computeds: {
	reversedMessage:
		function(){
			return this.message.split('').reverse().join('');
		}
}

Here is an example with getter and setter

$object->addComputed(
	'fullName',
	"return this.firstName+' '+this.lastName",
	"this.firstName=v[0];this.lastName=v[1]");

This code generates this content

computeds: {
	fullName: {
		get: function(){
			return this.firstName+' '+this.lastName
		},
		set: function(v){
			this.firstName=v[0];
			this.lastName=v[1]
		}
	}
}

Object Watchers

$object->addWatcher(
	"title",
	"console.log('Title change from '+ oldTitle +' to '+ newTitle)",
	['newTitle','oldTitle']);

addWatcher arguments

  1. (string) data to watch
  2. (string) function body
  3. (array) function argument(s) [optionnal]

This generates the content below

watch: {
	"title":
		function(newTitle,oldTitle){
			console.log('Title change from '+ oldTitle +' to '+ newTitle)
		}
}

Object Hooks

These are all the methods available to run a function at a given lifecycle

  • onBeforeCreate
  • onCreated
  • onBeforeMount
  • onMounted
  • onBeforeUpdate
  • onUpdated
  • onBeforeDestroy
  • onDestroyed
  • onActivated
  • onDeactivated

All hooks work in the same way, the underneath example can be applied for each hooks

hooks arguments

  1. (string) function's body
$object->onCreated("console.log('Page has been created !');");

This generates the content below

created:
	function(){
		console.log('Page has been created !');
	}

Directives

addDirective, addGlobalDirective arguments

  1. (string) directive's name
  2. (associative array) [hook => hook's function]

Object Directives

$object->addDirective('focus',['inserted'=>"el.focus()"]);

This generates the content below

directives: {
	focus: {
		inserted:
			function(el,binding,vnode,oldVnode){
				el.focus()
			}
	}
}

Global directives

$vueManager->addGlobalDirective('focus',['inserted'=>"el.focus()"]);

This generates the content below

Vue.directive('focus',{
	inserted:
		function(el,binding,vnode,oldVnode){
			el.focus()
		}
	});

Filters

addFilter, addGlobalFilter arguments

  1. (string) name
  2. (string) function body
  3. (array) function arguments [optionnal]

Object Filters

$object->addFilter(
	'capitalize',   
	"if(!value){"
		."return '';"
	."}"
	."value = value.toString();"  
	."return value.charAt(0).toUpperCase() + value.slice(1);",  
	["value"]);

This generates the content below

filters: {
	capitalize: function(value){
		if(!value){return '';}
		value = value.toString();
		return value.charAt(0).toUpperCase() + value.slice(1);
	}
}

Global Filters

$vueManager->addGlobalFilter(
	'capitalize',   
	"if(!value){"
		."return '';"
	."}"
	."value = value.toString();"  
	."return value.charAt(0).toUpperCase() + value.slice(1);",  
	["value"]);

This generates the content below

Vue.filter('capitalize',
	function(value){
		if(!value){return '';}
		value = value.toString();
		return value.charAt(0).toUpperCase() + value.slice(1);
	});

Components

addComponent, addGlobalComponent, importComponentObject arguments

  1. (VueJSComponent) component object

Vue Components

$component = new VueJSComponent('component-one');
$component->addData('framework','ubiquity');
$vue->addComponent($component);

This generates the content below

components: { "component-one": ComponentOne }

Local Components

$component = new VueJSComponent('component-one');
$component->addData('framework','ubiquity');
$vueManager->importComponentObject($component);

This generates the content below

const ComponentOne = {
	data:
		function(){
			return {framework: "ubiquity"}
		}
	};

Global Components

$component = new VueJSComponent('component-one');
$component->addData('framework','ubiquity');
$vueManager->addGlobalComponent($component);

This generates the content below

Vue.component('component-one',{
	data:
		function(){
			return {framework: "ubiquity"}
		}
	});

Mixins

addMixin, addGlobalMixin argument

  1. (VueJSComponent) mixin object

Object Mixins

$mixin = new VueJSComponent('mixin-one');
$mixin->addData('framework','ubiquity');
$vue->addMixin($mixin);

This generates the content below

mixins: [ MixinOne ]

Global Mixins

$mixin = new VueJSComponent('mixin-one');
$mixin->addData('framework','ubiquity');
$vueManager->addGlobalMixin($mixin);

This generates the content below

Vue.mixin({
	data: 
		function(){
			return {framework: "ubiquity"}
		}
	});

Extends

addGlobalExtend, extends argument

  1. (VueJSComponent) extend object

Component extends

$component = new VueJSComponent('component');
$componentOne = new VueJSComponent('component-one');  
$componentOne->addData('framework','ubiquity');
$componentOne->extends($component);
$vueManager->addGlobalComponent($componentOne);

This generates the content below

extends: "Component"

Global Extends

$extend = new VueJSComponent('extend-one');
$extend->addData('framework','ubiquity');
$vueManager->addGlobalMixin($extend);

This generates the content below

Vue.extend({
	data:
		function(){
			return {framework: "ubiquity"}
		}
	});

Global Observables

addGlobalObservable arguments

  1. (string) variable name
  2. (array) object
$vueManager->addGlobalObservable("state", ["count" => 0]);

This generates the content below

const state = Vue.observable({count: 0});

Configuration

VueManager Configuration

Axios

To enable axios

$vueManager->setAxios(true);

Components Configuration

Set Inherit Attributes

To enable setInheritAttrs

$component->setInheritAttrs(true);

Set Model

setModel arguments

  1. (string) props
  2. (string) events
$component->setModel('checked', 'change');

Adding Vue Object

addVue argument

  1. (VueJS) object vue
$vueManager->addVue($vue);

php-vuejs's People

Contributors

jcheron avatar jguillaumesio avatar qgorak avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

php-vuejs's Issues

VueJS version

VueJS has just released its version 3,
and the declaration of a VueJS application has changed slightly, compared to version 2.
Users must be allowed to choose the VueJS version they will integrate, which implies :

  • Defining the version in the php-vuejs configuration file.
  • Create JS code templates (in external files) to manage the specificities of the different versions.

And to upgrade php-vuejs to a future version of VueJS (v4...), just add some JS code templates
Nice :-)

VueJS generation refactoring

I think that the template generation approach is not the right one for the vueJS object.
VueJS is a JavaScript object, which can be generated directly from a php associative array with this method (see JavascriptUtils::arrayToJsObject).
No need for templates in this case.

Hooks conception problem

VueHooks

The VueHooks class is useless.
With java, it doesn't exist and the Hooks are stored in a Map, so they should probably be in an associative array in PHP.

Code repetitions

A lot of code repetition with the event adding methods, it should be factorized, since only the name of the event changes:

	public function onMounted(string $body) {
	    $vh=new VueHook($body);
		$this->addHook("mounted", body);
		$this->script['mounted']=$vh->__toString();
	}

Scrutinizer test failing

Trying to find a fix for issues happening during the scrutinizer test,
These are the problems :

Test tests/VueJSTest.php:testVueJSToString
[Error] Call to undefined method PHPMV\js\JavascriptUtils::arrayToJsObject()
#1 /home/scrutinizer/build/src/PHPMV/VueJS.php:30
#2 /home/scrutinizer/build/tests/VueJSTest.php:66

Test tests/VueJSTest.php:testVueJSComponent
[Error] Call to undefined method PHPMV\js\JavascriptUtils::arrayToJsObject()
#1 /home/scrutinizer/build/src/PHPMV/VueJSComponent.php:24
#2 /home/scrutinizer/build/tests/VueJSTest.php:80

Actually no idea why we have these errors as the test runs like a charm in local.
I maybe have a start of an answer, both of the tests failing use assertEqualsIgnoreNewLines()

Vue parts existence

PHP is not Java, and it is not always advisable to have a strictly equivalent design between the 2 languages.
To illustrate this:

  • The VueData class is nothing more than an associative array, object version (it inherits from ViewPart without doing anything more).

The addData method (and the other add...) is strange:

	public function addData(string $name,string $value):void {
	    $this->data->put($name,$value);
	    $this->script['data']=$this->data->__toString();
	}
  1. We add a key in data (ViewData)
  2. and we add a key in script, which makes the toString of the data

We have the impression that ViewData is useless, and that we are doing duplicate things (in data and in script).

Why not make things simpler, without being influenced by java:

	public function __construct() {
	    $this->data= [];
            ...
        }
	public function addData(string $name,$value):void {
	    $this->data[$name]=$value;
	}

	public function addDataRaw(string $name,string $value):void {
		$this->data[$name]="!!%$value%!!";//value must remain value
	}

Adding accceptance suite

codeception.yml

delete these 3 lines:

suites:
unit:
path: .

.scrutinitzer.yml

Added:

  • zip extension
  • dev.local in hosts
  • apache2 service with:
    • mode rewrite (for an eventual .htaccess usage)
    • a local site
  • Selenium
  • Google chrome
  • some commands to run before the test

see https://github.com/phpMv/php-reactjs/blob/9d86ced20a5ffbbf94c5ec0c7e7f5c713f9c8b1f/.scrutinizer.yml#L13-L35

Acceptance folder and config

_support folder

We can use exactly the same: https://github.com/phpMv/php-reactjs/tree/main/tests/_support

The local site (tests/www)

https://github.com/phpMv/php-reactjs/tree/main/tests/www

Acceptance test sample

public function tryToHelloMessage(AcceptanceTester $I) {
	$I->amOnPage('/HelloMessage');
	$I->wait(10);
	$I->canSee('Salut Thierry', 'body');
}

The tested url and component correspond to this file: https://github.com/phpMv/php-reactjs/blob/main/tests/www/include/HelloMessage.php

Setting up ci-tests

Code Quality

To be set up:
For monitoring the code quality:

Tests and coverage

The objective is to have a maximum coverage rate of the code by the tests (continuous) to avoid regression.

Installation

for phpUnit and codeCeption (see https://codeception.com/quickstart for more):
From the root of the project:

composer require "codeception/codeception" --dev

Unit testing setup (on windows):

vendor\bin\codecept.bat init unit

Update the .codeception.yml file (see https://github.com/phpMv/php-reactjs/blob/main/codeception.yml)

Test creation

It is possible to generate a test class from Codeception:

vendor\bin\codecept.bat g:test unit VueJSTest

Or from your IDE (With Eclipse, the generator adds the implementation of all the methods to be tested, that's the great advantage):
Select the tests folder, rigth click and then select New/PHP Unit Test case:
image

Then all that remains to be done is to implement the tests,
which will be run on Scrutinizer at each commit/push

Objective:
image

If we just want to run the tests locally:

vendor\bin\codecept.bat run unit

Test examples:

Code templates usage normalization

Template folder

Problem

Do not use a path for each template, this path must be globally defined, and possibly changed (depending on the VueJS version used):

$script=file_get_contents(__DIR__ . '/../template/computeds',true);

Solution

Create a VueJsLibrary class similar to React's one, and define the template folder (base template + sub folder rev)
see https://github.com/phpMv/php-reactjs/blob/main/src/PHPMV/core/ReactLibrary.php

Template parsing

Standardization between the 2 projects (php-reactjs and php-vuejs):

template names

  • extension tpl.js (tpl to indicate that it is a template, js if it is a javascript file (which allows to have syntax highlighting in the IDE))

variables replacement identification

  • To identify the replacement variables : you need a beginning and an end tag: for the moment I use the comment /*variableName*/.

Template parser usage

There is already a class dedicated to templates in php-ui-common, easy to use:
see https://github.com/phpMv/php-ui-common/blob/main/src/PHPMV/core/TemplateParser.php

Usage

$this->renderTemplate = new TemplateParser();
//load the template file
$this->renderTemplate->loadTemplatefile(ReactLibrary::getTemplateFolder() . '/renderComponent');
//parse the template with some variables
$result=$this->renderTemplate->parse([
				'selector' => $selector,
				'component' => $component
			]);

The associated template file:

https://github.com/phpMv/php-reactjs/blob/5c49fb8a5c714175a19dedd9ebdb405d3f181121/src/PHPMV/core/templates/rev1/renderComponent.tpl.js#L1-L2

see https://github.com/phpMv/php-reactjs/blob/main/src/PHPMV/react/ReactJS.php for an example

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.