interact with prismic.io API

 

Installation

npm install -g prismic-cli

prismic init prismic-io-project-name --template Quickstart-NodeJS

Run Server

npm run dev

or

sudo npm install -g nodemon
nodemon app.js

 

http://localhost:3000

 

Create new Custom types

Custom Types Name : Page

JSON Editor:

{
"Main" : {
"uid" : {
"type" : "UID",
"config" : {
"placeholder" : "UID"
}
},
"title" : {
"type" : "StructuredText",
"config" : {
"single" : "heading1",
"placeholder" : "Title..."
}
},
"description" : {
"type" : "StructuredText",
"config" : {
"multi" : "paragraph,em,strong,hyperlink",
"placeholder" : "Description..."
}
},
"image" : {
"type" : "Image"
}
}
}

Create content

UID : quickstart

Save + Publish

as-is

app.js

app.route('/').get((req, res) => {
res.render('index');
});

views/index.pug

extends ./layout.pug

block body
div.welcome
img(src='/images/powerstart.png', class='star')
h1 Welcome aboard!
p Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s
p Checkout our
a(href='http://prismic.io/quickstart') Quick Start Tutorial

to-be

app.js

// In app.js, in place of the block starting with "app.route('/')", put the following:

app.route('/').get(function(req, res) {
req.prismic.api.getByUID('page', 'quickstart').then((document) => {
res.render('index', { document });
});
});

views/index.pug

extends ./layout.pug

block body
div.welcome
img(src=document.data.image.url, class='star')
!= PrismicDOM.RichText.asHtml(document.data.title, ctx.linkResolver)
!= PrismicDOM.RichText.asHtml(document.data.description, ctx.linkResolver)

 

Quickstart : https://prismic.io/quickstart#?lang=javascript

Gallery : https://github.com/prismicio/nodejs-gallery-slice

REFERENCES : https://prismic.io/docs/javascript/templating/slices

Advertisements

N-gram : using the previous N-1 words in a sequence we want to predict the next word

a subsequence of n items (Phonemes/Syllables/Letters/Words/Anything else depending on the application) from a given sequence

Example : input=”the dog smelled like a skunk”

  • Unigram: n-gram of size 1
  • Bigram: n-gram of size 2

Example : the, the dog, dog smelled, smelled like, like a, a skunk, skunk

  • Trigram: n-gram of size 3

Example : “the dog”, “the dog smelled”, “dog smelled like”, “smelled like a”, “like a skunk” and “a skunk

How to predict next word : how likely is word x to follow word y

1)likelihood of x occurring in new text, based on its general frequency of occurrence
estimated from a corpus
“popcorn” is more likely to occur than “unicorn”
2)Condition the likelihood of x occurring in the context of previous words (bigrams, trigrams,…)
“mythical unicorn” is more likely than “mythical popcorn”

MORE : http://spring2015.cs-114.org/wp-content/uploads/2016/01/NgramModels.pdf

[ Laravel ] ORM relationship

 

One-to-One : User – hasOne – Phone

class User extends Model {

public function phone()
 {
 return $this->hasOne('App\Phone');
 }

}

USAGE using dynamic property

$phone = User::find(1)->phone;

// select * from users where id = 1

// select * from phones where user_id = 1 // assumes the foreign key of the relationship based on the model name

Override FK and localKey

return $this->hasOne('App\Phone', 'foreign_key');

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

Define Inverse relation : belongTo

class Phone extends Model {

public function user()
 {
 return $this->belongsTo('App\User'); // Eloquent look for user_id column on the phones table

// return $this->belongsTo('App\User', 'local_key'); 

// return $this->belongsTo('App\User', 'local_key', 'parent_key'); 
 }

}

 

One-to-many : blog – hasMany – comments

class Post extends Model {

public function comments()
 {
 return $this->hasMany('App\Comment');

// override FK, local_key

// return $this->hasMany('App\Comment', 'foreign_key');

// return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
 }

}

USAGE using dynamic property

$comments = Post::find(1)->comments;

$comments = Post::find(1)->comments()->where('title', '=', 'foo')->first(); // add futther constraints

Define Inverse relation : belongTo

class Comment extends Model {

public function post()
 {
 return $this->belongsTo('App\Post');
 }

}

Many-to-Many : User – belongsToMany – Role

table: users, roles, and role_user ( derived from the alphabetical order of the related model names ) and have user_id and role_id columns

class User extends Model {

public function roles()
 {
 return $this->belongsToMany('App\Role');

// return $this->belongsToMany('App\Role', 'user_roles'); // define mapping table name

// return $this->belongsToMany('App\Role', 'user_roles', 'user_id', 'foo_id'); // also define associate key
 }

}

class Role extends Model {

public function users()
 {
 return $this->belongsToMany('App\User');
 }

}

USAGE 

$roles = User::find(1)->roles;

 

hasManyThrough : short cut for access distant relation : Country – Post – User

countries
 id - integer
 name - string

users
 id - integer
 country_id - integer //
 name - string

posts
 id - integer
 user_id - integer //
 title - string

USAGE

$country->posts

define

class Country extends Model {

public function posts()
 {
 return $this->hasManyThrough('App\Post', 'App\User');

// return $this->hasManyThrough('App\Post', 'App\User', 'country_id', 'user_id'); // define FK
 }

}

Polymorphic Relations : model to belong to more than one other model, on a single association. Photo – belongsTo – Staff /or Order

Staff ( morphMany(‘App/Photo’, ‘imageable’) )- shared hasMany – Photo ( morphTo() )

Order ( morphMany(‘App/Photo’, ‘imageable’) ) – shared hasMany – Photo ( morphTo() )

 

class Photo extends Model {

public function imageable()
 {
 return $this->morphTo();
 }

}

class Staff extends Model {

public function photos()
 {
 return $this->morphMany('App\Photo', 'imageable');
 }

}

class Order extends Model {

public function photos()
 {
 return $this->morphMany('App\Photo', 'imageable');
 }

}

USAGE : retrieve photos from either staff /or order

$staff = Staff::find(1);

foreach ($staff->photos as $photo)
{
 //
}

USAGE : return either a Staff or Order instance

$photo = Photo::find(1);

$imageable = $photo->imageable;

Polymorphic relation table structure

staff
 id - integer
 name - string

orders
 id - integer
 price - integer

photos
 id - integer
 path - string
 imageable_id - integer //
 imageable_type - string // 

 

Many To Many Polymorphic Relations : Post/Video – polymorphic relation – Tag

Post ( morphToMany(‘App\Tag’, ‘taggable’) ) – shareBelongsToMany – Tag  ( morphedByMany(‘App\Post’, ‘taggable’) )

Video ( morphToMany(‘App\Tag’, ‘taggable’) ) – sharedBelongsToMany – Tag ( morphedByMany(‘App\Video’, ‘taggable’) )

 

posts
 id - integer
 name - string

videos
 id - integer
 name - string

tags
 id - integer
 name - string

taggables
 tag_id - integer
 taggable_id - integer //
 taggable_type - string // 

define

class Post extends Model {

public function tags()
 {
 return $this->morphToMany('App\Tag', 'taggable');
 }

}

class Tag extends Model {

public function posts()
 {
 return $this->morphedByMany('App\Post', 'taggable');
 }

public function videos()
 {
 return $this->morphedByMany('App\Video', 'taggable');
 }

}

[ Laravel ] authorization

“can” middleware

two arguments

( name of the action we wish to authorize, route parameter we wish to pass to the policy method )

In this case, since we are using implicit model binding, a Post model will be passed to the policy method. If the user is not authorized to perform the given action, a HTTP response with a 403 status code will be generated by the middleware.

ref : https://laravel.com/docs/5.6/authorization

[ Laravel ] Conner\Tagging\Providers\TaggingServiceProvider

Model declaration

class Article extends \Illuminate\Database\Eloquent\Model {
use Conner\Tagging\Taggable;
}

 

USAGE

$article->untag('Cooking'); // remove Cooking tag
$article->untag(); // remove all tags

$article->retag(array('Fruit', 'Fish')); // delete current tags and save new tags

 

table : 

  • tagging_tagged ( id, taggable_id, taggable_type, tag_name, tag_slug )
  • tagging_tags ( id, slug, name, suggest, count )
  • tagging_tag_groups ( id, slug )

 

ref : https://github.com/rtconner/laravel-tagging

[ Laravel ] EllipseSynergie\ApiResponse\Laravel\ResponseServiceProvider : handle response properly in your [API]

Installation in Laravel 5

config/app.php

EllipseSynergie\ApiResponse\Laravel\ResponseServiceProvider::class

app/Http/Controllers/ApiController.php

use EllipseSynergie\ApiResponse\Contracts\Response;

use App\Transformers\BookTransformer

 

class ApiController extends Controller

public function __construct(Response $response)
{
$this->response = $response;
}

errorNotFound()

return $this->response->errorNotFound('Book Not Found');
{
"error": {
"code": "GEN-NOT-FOUND",
"http_code": 404,
"message": "Book Not Found"
}
}

withItem()

return $this->response->withItem($book, new BookTransformer);
{
"data": {
"id": 1,
"title": "My name is Bob!.",
"created_at": {
"date": "2014-03-25 18:54:18",
"timezone_type": 3,
"timezone": "UTC"
},
"updated_at": {
"date": "2014-03-25 18:54:18",
"timezone_type": 3,
"timezone": "UTC"
},
"deleted_at": null
}
}

withPaginator()

return $this->response->withPaginator(
$books,
new BookTransformer
);
{
"data": [
{
"id": 1,
"title": "My name is Bob!",
"created_at": {
"date": "2014-03-25 18:54:18",
"timezone_type": 3,
"timezone": "UTC"
},
"updated_at": {
"date": "2014-03-25 18:54:18",
"timezone_type": 3,
"timezone": "UTC"
},
"deleted_at": null
},
{
"id": 2,
"title": "Who's your dady ?",
"created_at": {
"date": "2014-03-26 18:54:18",
"timezone_type": 3,
"timezone": "UTC"
},
"updated_at": {
"date": "2014-03-26 18:54:18",
"timezone_type": 3,
"timezone": "UTC"
},
"deleted_at": null
}
]
}

Classes for Transformers ( transform() )

use League\Fractal;

class BookTransformer extends Fractal\TransformerAbstract
{
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => (int) $book->yr,
'links' => [
[
'rel' => 'self',
'uri' => '/books/'.$book->id,
]
],
];
}
}

ref : https://github.com/ellipsesynergie/api-response,

https://fractal.thephpleague.com/transformers/

[ Laravel ] Antoineaugusti\LaravelSentimentAnalysis\SentimentAnalysis : dictionary of words that are categorised as positive, negative or neutral, and a naive bayes algorithm to calculate sentiment

$sentimentAnalysis = new SentimentAnalysis();

$sentimentAnalysis->decision($sentences); // negative, neutral or positive

$sentimentAnalysis->score($sentences); // closer to 1, the better! 

ref : https://github.com/AntoineAugusti/laravel-sentiment-analysis

[ Laravel ] alaouy/Youtube : PHP Facade/Wrapper for the Youtube Data API v3 ( Non-OAuth )

search clip

$params = [
'q' => 'Android',
'type' => 'video',
'part' => 'id, snippet',
'maxResults' => 50,

order' => 'date',
'videoEmbeddable' => 'true',
'publishedAfter' => ''
];

Youtube::searchAdvanced($params)

get videos infos

$videoInfos = Youtube::getVideoInfo(['videoId','anotherVideoId']);

ref : https://github.com/alaouy/Youtube

[ Laravel ] Passport : OAuth2 server for authentication API

include trait in User model

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}

 

app\Providers\AuthServiceProvider.php

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();

Passport::routes();
}
}

 

config/auth.php

'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],

'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],

 

resources\assets\js\app.js

Vue.component(
'passport-clients',
require('./components/passport/Clients.vue')
);

Vue.component(
'passport-authorized-clients',
require('./components/passport/AuthorizedClients.vue')
);

Vue.component(
'passport-personal-access-tokens',
require('./components/passport/PersonalAccessTokens.vue')
);

recompile asset with

npm run dev

 

creating clients and personal access tokens

passport-clients>

</passport-personal-access-tokens

 

== Client ==

Create client id for development

php artisan passport:client

 

Clients API

GET /oauth/clients :  all of the clients for the authenticated user

POST /oauth/clients :  create new clients

PUT /oauth/clients/{client-id} : update clients

DELETE /oauth/clients/{client-id}

 

== Authorize client ==

POST /oauth/token : return a JSON response containing access_token, refresh_token, and expires_in attributes

 

== PersonalAccessTokens == 

 

create PersonalAccessTokens

php artisan passport:client --personal

JSON API

GET /oauth/scopes :  list the scopes a user may assign to a personal access token

GET /oauth/personal-access-tokens : list all of the personal access tokens that the authenticated user has created

DELETE /oauth/personal-access-tokens/{token-id} : delete personal access tokens

 

== Protect route ==

'middleware' => 'auth:api'

 

== Consuming Your API With JavaScript ==

app/Http/Kernel.php

'web' => [
// Other middleware...
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

This Passport middleware will attach a laravel_token cookie to your outgoing responses. This cookie contains an encrypted JWT that Passport will use to authenticate API requests from your JavaScript application. Now, you may make requests to your application’s API without explicitly passing an access token

 

ref : https://laravel.com/docs/master/passport