Presentació

Mòdul Timetables

Creada per David Martinez

Organització

Projecte organitzat en dos paquets.

El primer instal·lable gràcies a composer i el segon l'utilitza en una aplicació Laravel.

Organització

El primer paquet s'encarrega de la API i guardar les vistes.

El segon paquet utilitza les vistes en una aplicació.

Packagist

Projecte pujat a packagist, llest per instal·lar en una aplicació Laravel.

Travis i studio

Al utilitzar studio per fer soft link i treballar sense haver de penjar-ho, cal dir-li a travis que ha de fer per trobar aquests paquets.

before_script:
  - sudo apt-get install unzip
  - wget https://github.com/davidmgilo/timetables/archive/master.zip -O ~/timetables-master.zip
  - unzip ~/timetables-master.zip
  - wget https://github.com/acacha/l5-repository/archive/master.zip -O ~/l5-repository-master.zip
  - unzip ~/l5-repository-master.zip
  - cp studio.travis.json studio.json
  - composer update
  - composer install --prefer-source --no-interaction --dev
						

Arquitectura

Arquitectura client-servidor (MVC). Cada part del projecte s'encarrega d'una feina concreta.

  1. El model s'encarrega de la definició de les dades.
  2. La vista s'encarrega d'interactuar amb l'usuari.
  3. El controlador s'encarrega de persistir les dades que rep i enviar les dades a la vista.

Exemples

Model

Vista

Controlador

Arquitectura API

El projecte l'utilitza per dividir entre el treball amb la base de dades (backend) i el treball amb el client (frontend). La comunicació és fa a través la API amb peticions.

Seguretat

El projecte utilitza laravel-passport per obtenir seguretat en api i autenticació per a seguretat web.

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

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

Base de dades

Imatge Base de dades

Base de dades- Relacions

Ús de relacions OneToMany i ManyToMany


public function classrooms()
{
	return $this->belongsTo(\Scool\Timetables\Models\Classroom::class);
}


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

Base de dades- Relacions

Exemples d'ús:


if ($request->has('user_id')) {
	$user_id = $request->input('user_id');
	$user = \App\User::find($user_id);
	$lesson->users()->save($user);
}

$lessons = $this->repository->with(['users'])->paginate(2);
						

En el segon exemple, s'indica que es vol rebre la lliçó amb Eager-Loading per obtenir les dades de l'usuari a la vegada.

API

Utilitza com a base el projecte l5-repository.

Inclou l'ús de repository pattern, transformers, validadors i respostes en Json des del controlador.

CRUD

Permet crear, modificar, borrar i consultar lliçons.

Exemple a la pàgina de la demo.

API components Vue - Props

Exemple

En aquest cas, el pare lessons envia les dades al fill lesson per mitja de propietats i espera que el fill indiqui quan es vol borrar o modificar una lliço.




deleteLesson: function(){
	this.$emit('lesson-deleted', this.index, this.lesson.id);
},
						

API components Vue - Store

Exemple

Un fitxer store s'encarrega de guardar la uri de la API per a que qualsevol component la pugui utilitzar

const store = {
    LESSONS_URI: 'api/v1/lessons/',
}
export default store

import store from './../store'
...
axios.get(store.LESSONS_URI...

API components Vue - EventBus

Exemple

L'utilitzo per comunicar dos components que no tenen relació pare-fill.


EventBus.$emit('created', response.data.message)

EventBus.$on('created', event => {
	console.log(event)
	this.messageOk = true
	this.errored = false
	this.message = event
})
						

Plantilla

Utilitza adminlte com a plantilla base.

La plantilla de la taula i el formulari són d'adminlte.

Formularis

Utilitzen el paquet acacha-forms i, per tant, inclouen un spinner que es pot utilitzar.

Aquest paquet, permet un control més fàcil dels errors al enviar els formularis. Aquest control permet millorar la interfície del formulari per a fer-ho més agradable a ulls del usuari.

Formularis - Exemple UserExperience

Permisos

Ús del paquet laravel permissions per donar permisos en les diferents parts del paquet

Exemples


$user = $this->createUser('Sergi Tur','sergitur@prova.com','123456');
$user->assignRole('manage lessons');

if(Auth::user()->can('add lessons')) return true;
return false;
						

Permisos i esdeveniments

Al crear un usuari, en la demo se li donen permisos per a poder crear i editar lliçons a través d'un esdeveniment

El codi es pot trobar al paquet de test.

Menú

El menu utilitza els permisos per mostrar o no un link segons si es tenen per a accedir-hi.

->linkIfCan('browse lessons', '/lessons', 'Lessons')
						

Usuari en la demo sense permisos: 'user@prova.com' amb contrasenya: '123456'

Social login

Basat en un controlador que escull la classe que s'encarrega de crear un usuari segons el tipus de xarxa social que sigui.

Social login


public static $services =[
      'github' => GithubAuth::class,
      'facebook' => FacebookAuth::class,
      'google' => GoogleAuth::class,
      'twitter' => TwitterAuth::class,
    ];

$authUser = self::$services[$provider]::findOrCreateUser($user);
						

Aquest estil permet ampliar la funcionalitat sense haver de tocar el codi ja previàment creat.

Email

Per enviar el mail de reset password, sobreescric la funció del model User.

 public function sendPasswordResetNotification($token)
{
	$this->notify(new CustomResetPasswordNotification($token));
}

Email

Utilitza una notificació com a controlador del enviament del mail.

La notificació és cuable.

I una vista com a cos del missatge.

Vista Pròpia

Mostra l'horari actual de l'usuari connectat.

Estructura

Dos components Vue. El primer és el pare que rep les dades i forma els events que passen al fill com a propietat.

El fill està fet en base a FullCalendar i utilitza les llibreries de fullcalendar i moment.

Codi

Per obtenir les lliçons de l'usuari, s'utilitza Lazy Eager Loading

Route::get('/user', function () {
    return Auth::user()->load('lessons');
}

Tests Unitaris

Comproven la API i la Autentificació

public function testNotAuthorizedIndex()
{
	$user = $this->loginNotAuthorized();
	$response = $this->get('/lessons');
	$this->assertEquals(403, $response->status());
}

public function testIndexNotLogged()
{
	$this->get('lessons');
	$this->assertRedirectedTo('login');
}

Tests Dusk

Comproven l'estat del front-end

public function testNotAuthorized()
{
	$this->browse(function (Browser $browser) {
		$browser->visit('/home')
			->assertPathIs('/login');
	});
}