curso laravel realtime messenger - parte 7 - mostrar errores en formularios

 @if( $errors->any())
              <b-alert show variant="danger">
                <ul>
                    @foreach($errors->all() as $error)
                    <li>
                       {{ $error }}   
                    </li>
                    @endforeach
                </ul>
              </b-alert>
           @else
              <b-alert show>
                Por favor, ingresa tus datos
              </b-alert>
           @endif

curso laravel realtime messenger - parte 6 - creando usuarios auth

luego de haber instalado el modulo de auth

debemos ejecutar las migrations, pero antes debemos crear nuestra base de datos y configurar los parametros de conexion en el archivo .env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=messenger
DB_USERNAME=root
DB_PASSWORD=

creamos la base de datos

mysql -u root -p

create database messenger


vamos anecesitar tener algunos usuarios de prueba creados inicialmente para poder trabajar.

entonces

vamos a database\seeds\DatabaseSeeder.php
y descomentamos la linea

$this->call(UsersTableSeeder::class);


y ejecutamos la sgt sentencia para crear esa clase seeder

php artisan make:seeder UsersTableSeeder

ahora editamos el archivo creado:

use Illuminate\Database\Seeder;
use App\User;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        User::create([
        'name'=>'israel',
        'email'=>'israelbazan76@gmail.com',
        'password' => bcrypt('123123')
        ])
    }
}




ahora si ya podemos ejecutar las migraciones....pero antes para evitar que nos de este error
pero nos va a salir el siguiente error

Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes


para resolver editar app\Providers\AppServiceProvider.php

 public function boot()
   {
      \Illuminate\Support\Facades\Schema::defaultStringLength(191);
   }

y finalmente


php artisan migrate --seed

curso laravel realtime messenger - parte 5 - adaptando cabecera navegador a bootstrap-vue

la cabecera de navegacion se encuentra en

resources\views\layouts\app.blade.php

asi que debemos editar ese archivo,

quedandonos

<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                            {{ csrf_field() }}
</form>
<div id="app">
       <b-navbar toggleable="md" type="dark" variant="info">

           <b-navbar-toggle target="nav_collapse"></b-navbar-toggle>

            <b-navbar-brand  href="{{ url('/') }}">
            {{ config('app.name', 'Laravel') }}
            </b-navbar-brand>

            <b-collapse is-nav id="nav_collapse">

            <!-- Right aligned nav items -->
            <b-navbar-nav class="ml-auto">

                  @guest
                  <b-nav-item href="{{ route('login') }}">Ingreso</b-nav-item>
                    <b-nav-item href="{{ route('register') }}">Registro</b-nav-item>
                  @else
                  <b-nav-item-dropdown right>
                    <!-- Using button-content slot -->
                    <template slot="button-content">
                      <em>{{ Auth::user()->name }}</em>
                    </template>
                    <b-dropdown-item @click="logout">Salir</b-dropdown-item>
                  </b-nav-item-dropdown>
                  @endguest

            </b-navbar-nav>

            </b-collapse>
        </b-navbar>


   
        @yield('content')
    </div>



donde el link para salir llama a una funcion llamada logout.
que la vamos a definir en

resources\assets\js\app.js


asi:

const app = new Vue({
    el: '#app',
    methods:{
    logout(){
    document.getElementById('logout-form').submit();
    }
    }
});

el cual llamar al evento submit del formulario que hemos sacado afuera del cuerpo principal




curso laravel realtime messenger parte 3 - adaptando login a bootstrap-vue

originalmente tenemos:
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">

donde col-md-8 significa que el sistema de grilla de 12 columnas. el cuerpo va a ocupar 8 y va a usarse 2 columnas vacias a ambos lados. para que de esa manera quede centrado.

reemplazar por:
<b-container>
    <b-row> 
       <b-col>
       </b-col>
       <b-col cols="8"> 
       </b-col>
       <b-col>
       </b-col>
    </b-row>
</b-container>

o mejor por:
<b-container>
  <b-row align-h="center"> 
      <b-col cols="8"> 
         ...
      </b-col>
  </b-row>
</b-container>


lo que esta dentro del b-col cols="8" 

<div class="panel panel-default">
            <div class="panel-heading">Login</div>

            <div class="panel-body">
             //----aqui esta el formulario
            </div>
</div>

lo reemplazaremos por el componente b-card

<b-card header="featured"
header-tag="header"
footer="Card Footer"
footer-tag="footer"
title="Title">
    <p class="card-text">Header and footers using props.</p>
    <b-button href="#" variant="primary">Go somewhere</b-button>
</b-card>


curso laravel realtime messenger - parte 2 bootstrap-vue

instalamos el scafolding para manejo de usuarios (login y registro)

desde la carpeta del proyecto:

php artisan make:auth

--------------------

instalamos bootstrap-vue

npm i bootstrap-vue

en resources/js/app.js

import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'

Vue.use(BootstrapVue);
y en resources/js/bootstrap.js
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Hay que volver a crear en resources la carpeta assets/sass y adentro app.scss en donde pegaremos las gsts lineas: 
@import "~bootstrap/dist/css/bootstrap.css"; @import "~bootstrap-vue/dist/bootstrap-vue.css";
luego, en webpack.mix.js, debera quedar asi:
mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css');




compilamos

php run dev



para probar si realmente ya hemos cargado bootstrap-vue

podemos editar la pagina de login y le pegamos al codigo un bloque que hace referencia a un componente. en este caso al de alert.

resources\views\auth\login.blade.php

 <b-alert show>
                        Por favor, ingresa tus datos
 </b-alert>

curso laravel realtime messenger - parte 1 configuraciones iniciales

tenemos que bajarnos las librerias de javascript necesarias, esto lo hacemos con npm
pero antes editamos el archivo donde se manejan estas dependencias

package.json

dejamos unicamente estas:

"devDependencies": {
        "axios": "^0.17",
        "cross-env": "^5.1",
        "laravel-mix": "^1.0",
        "vue": "^2.5.7"
    }

como hemos sacado las referencias a jquery, bootstrap-sass y lodash
las quitamos tambien del archivo

resources\assets\js\bootstrap.js

y en el archivo

webpack.mix.js

lo dejamos asi:

mix.js('resources/assets/js/app.js', 'public/js');

--le hemos quitado la parte donde trabajaba con la carpeta sass, de hecho tambien podriamos eliminarla del proyecto.
resources\assets\sass


ahora si, compilamos el proyecto:

npm run dev

esto generara en public/js el archivo app.js
como se indicaba en webpack.mix.js


laravel sincronizar proyecto con github

desde la carpeta del proyecto nuevo:

1)
git init

2)

git add -A

3)

git commit -m "initial commit"

4)
ir a la pagina de github

-crear un nuevo repositorio
-copiar la direccion https del repositorio (p.e https://github.com/israelbazan76/messenger.git)

5)
en la consola:

git remote add origin https://github.com/israelbazan76/messenger.git

6)

git push origin master






laravel crear proyecto con composer



si trabajamos con xampp:

1)
abrir una consola e ir hasta la carpeta httdocs,

composer create-project --prefer-dist laravel/laravel nombre_del_proyecto "5.5.*"


2)
- ir a la carpeta del proyecto creado
- renombrar el archivo oculto .env.example por .env:

rename .env.example .env


3) generar la clave de la aplicacion

php artisan key:generate


------------ opcional --------------

crear un virtual host

1) editar el archivo
C:\xampp729\apache\conf\extra\httpd-vhosts.conf

<VirtualHost *:80>
  ServerName messenger.local
  DocumentRoot "C:/xampp729/htdocs/messenger/public"
</VirtualHost>

2)editar el archivo
C:\Windows\System32\drivers\etc\hosts

127.0.0.1      messenger.local

----------------------------------------

ya podemos levantar el servidor apache
y en el navegador acceder a la url:

http://messenger.local:80






laravel 5.7 notificaciones database pusher

1) ir a pusher.com y registrarse

2) crear una new app

donde 
frontend: vanilla js
backend: laravel
cluster: us2

3) instalar pusher en nuestra aplicacion

composer require pusher/pusher-php-server
4) ir a la pestana de App Keys
y tomar la informacion de alli para completar los datos en .env

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=


y en resources/js/bootstrap.js

import Echo from 'laravel-echo'

window.Pusher = require('pusher-js');

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'XXXXXX',
    cluster: 'us2',
    encrypted: true
});


5)Crear en resource/components NotificationComponent.vue

<template>
<li class="nav-item d-md-down-none">
                <a class="nav-link" href="#" data-toggle="dropdown">
                    <i class="icon-bell"></i>
                    <span class="badge badge-pill badge-danger">{{notifications.length}}</span>
                </a>
                <div class="dropdown-menu dropdown-menu-right">
                    <div class="dropdown-header text-center">
                        <strong>Notificaciones</strong>
                    </div>
                    <li v-for="notification in notifications" :key="notifications.id">
                    <a class="dropdown-item" href="#">
                        <i class="fa fa-envelope-o"></i> {{notification.data.datos.articulos.titulo}}
                        <span class="badge badge-success">{{notification.data.datos.articulos.activos}}</span>
                    </a>
                    
                    </li>
                </div>
            </li>
</template>
<script>
export default {
props: ['notifications'],
        data(){
            return {
            }
        }
    }
</script>


6) agregar este componente en resources/js/app.js

Vue.component('notification', require('./components/NotificationComponent.vue'));

const app = new Vue({
    el: '#app',
    data:{
    menu:0,
    notifications:[]
    },
    created(){
    let me = this;
    axios.get('/notifications').then(function(response){
    console.log(response.data)
    me.notifications=response.data;
    }).catch(function(error){
    console.log(error);
    });
    }
});

7) en la plantilla principal reemplazar el codigo de cabecera donde se mostrabalas notificaciones por este componente:

principal.blade.php

<notification :notifications="notifications"></notification>  

8) vamos a usar  el canal "database" que es donde la informacion de las notificaciones se guardan en una tabla

php artisan notifications:table

php artisan migrate

como en laravel cada notificacion es representada por una simple clase, vamos a crear una

php artisan make:notification NotifyAdmin
lo que creara la carpeta Notifications dentro de App y dentro la clase NotifyAdmin

class NotifyAdmin extends Notification
{
   
    public $GlobalDatos;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(Array $datos)
    {
      $this->GlobalDatos = $datos;
    }

    public function via($notifiable)
    {
        return ['database'];
    }

    public function toDatabase($notifiable)
    {
        return ['datos' => $this->GlobalDatos];
    }


8) creamos NotificationController:

public function getAllByUser()
    {
    $user =  \Auth::user();
       
       //return Notification::where('notifiable_id','=',$user->id)->get();
       

        return $user->notifications;
     
    }
9)
creamos la ruta de este metorod en web.php

Route::get('/notifications','NotificationController@getAllByUser')->middleware('auth');


10) en este ejemplo cada vez que se crea un nuevo producto se va a crear una notificacion por cada usuario con la cantidad de articulos activos (condicion=1)

entonces en ArticuloController->store

...despues del save

$numActivos = DB::table('articulos')->where('condicion','=','1')->count();
       
        $arregloDatos = [
            'articulos' => [
                'activos' =>$numActivos,
                'titulo' => 'Articulos activos'
            ]
        ];
        $users = \App\User::all();
        foreach ($users as $user) {
            \App\User::findOrFail($user->id)->notify(new \App\Notifications\NotifyAdmin($arregloDatos));
        }

Abrir varias terminales de Ubuntu en Windows

instalar TMUX

1)

sudo apt-get install tmux

2)

tipear tmux

3)

por ejemplo podemos ir al disco C

cd /mnt/c

y desde ahi

Here is a list of a few basic tmux commands:
  • Ctrl+b " — split pane horizontally.
  • Ctrl+b % — split pane vertically.
  • Ctrl+b arrow key — switch pane.
  • Hold Ctrl+b, don’t release it and hold one of the arrow keys — resize pane.
  • Ctrl+b c — (c)reate a new window.
  • Ctrl+b n — move to the (n)ext window.
  • Ctrl+b p — move to the (p)revious window.
Other thing worth knowing is that scrolling is enabled by pressing Ctrl+b PgUp/PgDown

instalar ubuntu 16.04 en windows



1) ir a Settings -> Update & Security -> For Developers

2) habilitar Developer Mode

3) ir a Control Panel -> Programs -> Turn Windows features on or off

4) buscar y habilitar la opcion Windows Subsystem for Linux

5) reinicar la PC.

6) ir al Windows Store buscar Ubuntu e instalar Ubuntu 16.04 LTS

7) abrir Ubuntu e indicar el usuario y password para Ubuntu (no es necesario que coincidan con los de windows)

ubuntu 16.04 instalar php7.x

sudo apt-add-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.x

ubuntu 16.04 instalar npm

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs

laravel login y logout

Route::group(['middleware' => ['guest']], function () {
Route::get('/', 'Auth\LoginController@showLoginForm');
Route::match(['get','post'],'/login', 'Auth\LoginController@login')->name('login');
});

Route::match(['get','post'],'/logout','Auth\LoginController@logout')->name('logout')->middleware('auth');

Route::match(['get','post'],'/ se uso en vez de post
para evitar la exception MethodNotAllowedHttpException que dispara cuando, estando logueado, se tipea en la url /login

laravel maneja "automaticamente" a traves del middleware RedirectIfAuthenticated que cuando se esta logueado y se tipee en la url
la barra "/" o "/login" te redireccione a la ruta que hayas denominado como "home"


aunque el logout se puede  manejar para evitar ataques Cross se va a manejar a traves del method POST, entonces en la vista

<div class="dropdown-menu dropdown-menu-right">
                    <div class="dropdown-header text-center">
                        <strong>Cuenta</strong>
                    </div>
                    <a class="dropdown-item" href="#"><i class="fa fa-user"></i> Perfil</a>
                    <a class="dropdown-item" href="#" onclick="event.preventDefault(); document.getElementById('frm-logout').submit();"><i class="fa fa-lock"></i> Cerrar sesión</a>
                </div>
                <form id="frm-logout" action="{{ route('logout') }}" method="POST" style="display: none;">
                  {{ csrf_field() }}
                </form>

y en el controller:

 public function logout(Request $request)
    {
        if ($request->isMethod('post')) {
             Auth::logout();
             $request->session()->invalidate();
             return redirect('/');
        }
        return back();
     
    }




laravel crear data de prueba

por ejemplo para crear usuarios

1) creamos una clase seeder
php artisan make:seeder UsersTableSeeder

(la cual se creara dentro de database/seeds)

2) editamos el cuerpo de la clase USersTableSeeder
para indicar que modelo usaremos para crear registros y la cantidad de registros a crear

use Illuminate\Database\Seeder;
use App\User;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
        factory(User::class, 5)->create();
    }
}

3) ahora debemos crear la clase factory que se encuentra en database/factories
use Faker\Generator as Faker;

$factory->define(App\User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
        'remember_token' => str_random(10),
    ];
});

4) EN la clase DatabaseSeeder, indicamos las llamadas a los seeders que se invocaran con una llamada general

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
         $this->call(UsersTableSeeder::class);

    }
}

5)
para llamar al run de databaseSeeder
php artisan db:seed
para llamar al run del seeder en particular

php artisan db:seed --class=UsersTableSeeder

laravel localization language


modificar

config/app.php

'locale' => 'es'

debe existir, sino hay que crearla, la carpeta

resources/lang/es

si usamos en un controller por ejemplo la siguiente
return back()->withErrors(['usuario'=>trans('auth.failed')]);
     
quiere decir que existe el archivo auth.php en resources/lang/es
con la sgt estructura:

<?php

return [
    'failed' => 'Los datos ingresados no coinciden con nuestros registros.',
];

no olvidar limpiar la cache de la config:

php artisan config:cache


se puede descargar la carpeta es desde este repositorio
https://github.com/hosmelq/lang-spanish

react native 0.57 crear y ejecutar una primer aplicacion

1)
desde la consola

react-native init MiAplicacion

2) ir a la carpeta creada de la aplicacion y desde ahi:

npm add @babel/runtime

3) ir a android Studio

file->open

ir hasta la carpeta del proyecto y click en el archivo "android"

4) abrir AVD Manager

del listado de Your Virtual Devices click en el boton verde de play para lanzar ese emulador

5) desde la consola y dentro de la carpeta de la aplicacion creada:

react-native run-android


6) Si todo esta ok deberia aparecer en la pantalla del emulador el siguiente texto de prueba:

   Welcome to React Native!
   To get started, edit App.js
   Double tap R on your keyboard to reload,
   Shake or press menu button for dev menu


el cual se encuentra en App.js en la raiz del proyecto

react native 0.57 seteos iniciales

informacion obtenida de
https://facebook.github.io/react-native/docs/getting-started.html


1) instalar chocolatey, un administrador de paquetes para windows:

desde la consola

@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"


2) instalar dependencias necesarias

choco install -y nodejs.install python2 jdk8

3) instalar el react cli (command line interface)

npm install -g react-native-cli

4) instalar android studio

5) al instalar android studio se instalara el ultimo sAndroid dk disponible pero para esta version de react native vamos a necesitar la

Android 8.0 (Oreo)

entonces vamos al SDK Manager
click en la pestana de SDK Platforms

(click en el checkbox inferior-derecha de "show package details")

check en Android 8.0 desplegar y verificar que esten tambien marcadas las opciones

  • Android SDK Platform 26 
  • Google APIs Intel x86 Atom_64 System Image


click en "Apply".

6)setear en las variables de entorno android_home con el valor del sdk de android

ANDROID_HOME
usalmente se encuentra en esta direccion:

c:\Users\YOUR_USERNAME\AppData\Local\Android\Sdk

7) crear un nuevo AVD android virtual device

click en el icono de AVD MAnager

click en +new Virtual Device

seleccionar el tab de Phone y click en Next

luego Select the "x86 Images" tab, then look for the Oreo API Level 26, x86_64 ABI image with a Android 8.0 (Google APIs) target.

listo
habra tambien que Install HAXM que seguramente te pedira al momento de hacerle clik en el boton triangular vede de play





ubuntu error cuando ejecutamos php.exe PHP Startup: Unable to load dynamic library '/usr/lib/php/20160303/php_mbstring.dll

PHP Startup: Unable to load dynamic library '/usr/lib/php/20160303/php_mbstring.dll



editar el php.ini

comentar con un punto-y-coma al inicio, la siguiente linea

extension=php_mbstring.dll
;extension=php_mbstring.dll ; commented out

para saber donde se encuentra este archivo:

php -i | grep -i "Loaded Configuration File"

a veces si no se tiene permisos de escritura hay que modificarlo asi

sudo chmod 755 /etc/php/7.1/cli/php.ini

sublime3 psr2 plugin

1) Ctrl+shift+p

y buscamos "instALL PACKAGE"

2) luego buscamos "codeFormatter" le damos enter para que se instale

3) vamos a

preferences->package settings->Codeformatter->Settings default

y editar la variable

  "php_path": "",

con la ruta donde se tiene instalado el php.exe

esto se puede averiguar tipeando en consola

whereis php

en mi caso es /usr/bin/php7.1

quedaria 

  "php_path": "/usr/bin/php7.1",

listo!

4) como usarlo?  

abrir el archivo que quieras formatear 

ctrl+shift+p

tipear "format code" y enter 


(para archivos php esta por default seteado para que lo formatee en psr-2)

sublime3 ocultar panel lateral + ver archivo actual en arbol de archivos

ir a
preferences->key bindings

y copiar las sgts sentencias dentro del sublime.keymap-User

// Toggle the Sidebar
{ "keys": ["ctrl+\\"], "command": "toggle_side_bar" }, 
// BONUS: Reveal current file on the sidebar tree
{ "keys": ["ctrl+shift+r"], "command": "reveal_in_side_bar" },



curso vue laravel paginacion

1-Modificar el controlador para que en el metodo index(el de listar) se devuelva una respuesta
que contemple las variables necesarias para la paginacion
2-Crear un componente que lea las variables que devuelve el controler y maneje la paginacion
3-Registrar el componente de paginacion en el app.js


CategoriaController.php:

public function index(Request $request)
    {
       
        $categorias = Categoria::paginate(3);
        $response = [
            'pagination' => [
                'total' => $categorias->total(),
                'per_page' => $categorias->perPage(),
                'current_page' => $categorias->currentPage(),
                'last_page' => $categorias->lastPage(),
                'from' => $categorias->firstItem(),
                'to' => $categorias->lastItem()
            ],
            'data' => $categorias
        ];
        return response()->json($response);
    }


creamos en resources/js/components/PaginationComponent.vue:
(la parte de html usa el estilo de coreui)

<template>
    <nav>
      <ul class="pagination">
        <li class="page-item">
            <a class="page-link" @click.prevent="changePage(pagination.current_page - 1)" :disabled="pagination.current_page <= 1">Ant</a>
        </li>
        <li v-for="page in pages" class="page-item" :class="isCurrentPage(page) ? 'active' : ''">
                <a class="page-link" @click.prevent="changePage(page)">{{ page }}</a>
        </li>
        <li class="page-item">
            <a class="page-link" @click.prevent="changePage(pagination.current_page + 1)" :disabled="pagination.current_page >= pagination.last_page">Sig</a>
        </li>
      </ul>
    </nav>
   
</template>

<style>
    .pagination {
        margin-top: 40px;
    }
</style>

<script>
    export default {
        props: ['pagination', 'offset'],
        methods: {
            isCurrentPage(page) {
                return this.pagination.current_page === page;
            },
            changePage(page) {
                if (page > this.pagination.last_page) {
                    page = this.pagination.last_page;
                }
                this.pagination.current_page = page;
                this.$emit('paginate');
            }
        },
        computed: {
            pages() {
                let pages = [];
                let from = this.pagination.current_page - Math.floor(this.offset / 2);
                if (from < 1) {
                    from = 1;
                }
                let to = from + this.offset - 1;
                if (to > this.pagination.last_page) {
                    to = this.pagination.last_page;
                }
                while (from <= to) {
                    pages.push(from);
                    from++;
                }
                return pages;
            }
        }
    }
</script>


en app.js

Vue.component('pagination', require('./components/PaginationComponent.vue'));

ya se puede usar el componente, dentro del componente de categoria que maneja toda la grilla de categorias

<pagination v-if="pagination.last_page > 1" :pagination="pagination" :offset="5" @paginate="fetchRecords()"></pagination>
...
<script>
    export default {
        data(){
            return {
                nombre:'',
                descripcion:'',
                arrayCategorias:[],
                modal:0,
                tituloModal:'',
                accion:'',
                errors:[],
                categoria_id:0,
                pagination: {
                    'current_page': 1
                }
            }
        },
        mounted() {
              this.fetchRecords();
        },
        methods:{
            fetchRecords() {
                axios.get('/categorias?page=' + this.pagination.current_page)
                .then(response => {
                    //console.log(response);
                    this.arrayCategorias = response.data.data.data;
                    this.pagination = response.data.pagination;
                })
                .catch(error => {
                    console.log(error.response.data);
                });
            },

curso vue laravel crud

ejemplo CRUD Categoria

creamos un componente para categoria, resources/js/components/CategoriaComponent.vue
que manejara todo el modulo crud de Categoria

en resources/js/app.js

hacemos referencia al componente y definimos el tag "categoria" para referrirnos al componente

Vue.component('categoria', require('./components/CategoriaComponent.vue'));


el componente tiene las sgts partes:
template: aqui va todo el html
script: codigo javascript
style: estilos particulares a usarse en este componente

para el CREAR

dentro del template tendremos un boton que abrira una ventana modal con los campos para registrar una nueva categoria

 <button type="button" @click="abrirModal('registrar')" class="btn btn-secondary" >
                            <i class="icon-plus"></i>&nbsp;Nuevo
 </button>

y la estructura de la ventana modal
    <div class="modal fade"  tabindex="-1" :class="{'mostrar':modal}" role="dialog" aria-labelledby="myModalLabel" style="display: none;" aria-hidden="true">
            <h4 class="modal-title" v-text="tituloModal"></h4>
 <input type="text" v-model="nombre" class="form-control" >
     <input type="text" v-model="descripcion" class="form-control" >
      <div v-show="errors.length" class="form-group row">
                                    <div class="col-md-12">
                                        <div  class="alert alert-danger" role="alert" v-for="error in errors" v-text="error">
                                            
                                        </div>
                                    </div>

                                </div>                            
<button type="button" class="btn btn-secondary" @click="cerrarModal()">Cerrar</button>
                            <button type="button" v-if="accion=='guardar'" @click="registrarCategoria()" class="btn btn-primary">Guardar</button>
                                       

entonces en la seccion de script

 export default {
        data(){
            return {
                nombre:'',
                descripcion:'',
                modal:0,
                tituloModal:'',
                accion:'',
                errors:[]
            }
        },
        methods:{
           registrarCategoria(){
                if(!this.validarCategoria()){
                    return;
                }
                let me=this;
                axios.post('/categorias/registrar',{
                    'nombre':me.nombre,
                    'descripcion':me.descripcion
                }).then(function (response) {
                // handle success
                    me.cerrarModal();
                    me.listarCategorias();
                })
                .catch(function (error) {
                // handle error
                    console.log(error);
                });
            },
            abrirModal(accion,data=[]){
                switch(accion){
                    case 'registrar':
                    {
                      this.modal = 1;
                      this.nombre = '';
                      this.descripcion = '';
                      this.tituloModal = 'Registrar nueva categoria';
                      this.accion='guardar';
                      //console.log('registrar');
                      break;
                    }
            
        }

donde:

 modal:0, // indica si se muestra (1) o no (0) la ventana modal
                tituloModal:'', //titulo de la ventana modal, es variable porque se usara el mismo para actualizar
                accion:'', //accion actual, registrar o actualizar
                errors:[] // array con los mensajes de error



para ACTUALIZAR

tenemos un icono de editar por cada registro del listado

<tr v-for="categoria in arrayCategorias.data" :key="categoria.id">
                                    <td>
                                        <button type="button" class="btn btn-warning btn-sm"
                                        @click="abrirModal('actualizar',categoria)" >
                                          <i class="icon-pencil"></i>
                                        </button> &nbsp;

en este caso le enviamos los datos de categoria actual para llenar los campos del formulario de la ventana modal.

y en la ventana modal cuando se abra el boton dira actualizar y llamara a actualizarCAtegoria
 <button type="button" v-if="accion=='actualizar'" @click="actualizarCategoria()"class="btn btn-primary">Actualizar</button>


abrirModal(accion,data=[]){
                switch(accion){
                    case 'actualizar':
                    {
                      this.modal = 1;
                      this.nombre = data['nombre'];
                      this.descripcion = data['descripcion'];
                      this.tituloModal = 'Actualizar categoria';
                      this.categoria_id = data['id'];
                      
                      this.accion='actualizar';
                      //console.log('registrar');
                      break;
                    }
                }
            }
 actualizarCategoria(){
                if(!this.validarCategoria()){
                    return;
                }
                let me=this;
                axios.put('/categorias/actualizar',{
                    'nombre':me.nombre,
                    'descripcion':me.descripcion,
                    'id':me.categoria_id,

                }).then(function (response) {
                // handle success
                    me.cerrarModal();
                    me.listarCategorias();
                })
                .catch(function (error) {
                // handle error
                    console.log(error);
                });
            },


en nuestro archivo de rutas routes/web.php

tenemos

Route::get('/categorias', ['uses'=>'CategoriaController@index']);
Route::post('/categorias/registrar', ['uses'=>'CategoriaController@store']);
Route::put('/categorias/actualizar', ['uses'=>'CategoriaController@update']);

entonces, el problema es que si desde la url apuntamos a esas rutas
por ejemplo http://localhost:8000/categorias

escupira en el browser en forma de json la categorias de la tabla.
entonces le vamos a agregar una minima seguridad, haciendo que cada uno de los metodos del controller solo respondan si la peticion fue hecha a traves de una llamada ajax. de lo contrario se redirigira a la pagina raiz

en la primera linea del cuerpo de cada metodo agregar:

if(!$request->ajax()) return redirect("/");





curl ubuntu

si tienes un archivo que haga llamadas curl

para ejecutarlo

php -f miarchivo.php

si te sale
PHP Fatal error: Call to undefined function curl_init()

quiere decir que no está instalado el modulo de curl, esto tambien se puede comprobar
<?php var_dump(extension_loaded('curl')); ?>

y si da false,

sudo apt-get install php7.1-curl

para versiones de php 7.1.x

curso vue.js laravel conceptos

es un framework javascript progresivo para crear interfaces de usuario pudiendo agregarsela a la parte de tu aplicacion que necesites que sea mas intuitiva e interactiva.diviendo una pagina web en componentes reutilizables (con su propio html, css y javascript).
vue.js es reactivo es decir que si si la data se modifica el front que la muestra tambien(data binding)

https://vuejs.org/v2/guide/installation.html

descargamos la version de desarrollo y la de produccion(es la de desarrollo minificada y sin comentarios) haciendo clik sobre ambas opciones,
y la guardamos dentro de una carpeta de nuestra aplicacion (llamada por ejemplo js)

https://getbootstrap.com/docs/4.1/getting-started/introduction/

copiamos de esta pagina la direccion cdn de bootstrap

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css" integrity="sha384-Smlep5jCw/wG7hdkwQ/Z5nLIefveQRIY9nfy6xoR1uRYBtpZgI6339F5dgvm/e9B" crossorigin="anonymous">

y lo pegamos en el head de nuestro proyecto.





curso vue.js laravel crear proyecto

crear un db a traves de phpmyadmin

http://localhost/phpmyadmin/

la llamaremos dbsistemalaravel

instalar laravel

composer global require "laravel/installer"

vamos a la ruta_xampp/htdocs

y por la consola creamos el proyecto asi
laravel new sislaravel

luego abrimos el proyecto(carpeta) en nuestro editor
duplicamos el archivo .env.example y lo lllamamos .env

luego generamos una key de encriptacion a traves de la consola

php artisan key:generate

luego podemos levantar el servidor interno

php artisan serve

y acceder a nuestra aplicacion a traves de la sgt url

http://127.0.0.1:8000/




curso node llamar a un service web api

primero vamos a instalar yargs
y setear que reciba (esta vez sin un comando de por medio) el argumento
de la direccion de la que se quiere saber su clima


const argv=require('yargs').options(
{
   direccion:{
alias:'d',
demand:true,
desc: 'direccion a traer el clima'
}
}).
argv;

console.log(argv.direccion);


entonces si llamamos

node app -d "buenos aires argentina"

obtendremos

buenos aires argentina


vamos a instalar ahora un paquete para poder hacer llamadas a apis externas,
en este caso usaremos Axios (tambien puede ser request)

npm install axios --save

recordar que ponemos el --save para que se registre el paquete en el package.json como un dependencia, de lo contrario, se bajara la libreria sin registrarse la dependencia.

si se quiere instalar una version en especifico simplemente la escribimos antecediendole una arroba:

npm installa axios@0.18.0 --save

ahora ya podemos utilizarlo para llamar al webservice de google de geocoding

const axios=require('axios');

const urlEncoded = encodeURIComponent(argv.direccion);//para que convierta espacios

const apiKey = "AIzaSyBlRKjSjinm50447yd_qWAjvzojhWND7Ip-w";

axios.get(`https://maps.googleapis.com/maps/api/geocode/json?address=${urlEncoded}&key=${apiKey}`)
  .then(function (response) {
    console.log(JSON.stringify(response.data));
  })
  .catch(function (error) {
    console.log(error);
  });


usamos response.data
para que por consola nos muestre solo los datos de la data de geocoding
y JSON.stringify(response.data)
para que nos muestre los datos de los objetos / arrays que trae Data sino no los podremos ver.

por consola los datos apareceran uno al lado del otro si queremos que se vean en distintas lineas
y con margenes usamos

JSON.stringify(response.data,undefined,2));

la respuesta sera algo asi

 {                                                   
 "results": [                                       
   {                                                 
     "address_components": [                         
       {                                             
         "long_name": "Buenos Aires",               
         "short_name": "CABA",                       
         "types": [                                 
           "locality",                               
           "political"                               
         ]                                           
       },                                           
       {                                             
         "long_name": "Buenos Aires",               
         "short_name": "CABA",                       
         "types": [                                 
           "administrative_area_level_1",           
           "political"                               
         ]                                           
       },                                           
       {                                             
         "long_name": "Argentina",                   
         "short_name": "AR",                         
         "types": [                                 
           "country",                               
           "political"                               
         ]                                           
       }                                             
     ],                                             
     "formatted_address": "Buenos Aires, Argentina", 
     "geometry": {                                   
       "bounds": {                                   
         "northeast": {                             
           "lat": -34.5265464,                       
           "lng": -58.33514470000001                 
         },                                         
         "southwest": {                             
           "lat": -34.7051011,                       
           "lng": -58.5314522                       
         }                                           
       },                                           
       "location": {                                 
         "lat": -34.6036844,                         
         "lng": -58.3815591                         
       },                                           
       "location_type": "APPROXIMATE",               
       "viewport": {                                 
         "northeast": {                             
           "lat": -34.5265464,                       
           "lng": -58.33514470000001                 
         },                                         
         "southwest": {                             
           "lat": -34.7051011,                       
           "lng": -58.5314522                       
         }                                           
       }                                             
     },                                             
     "place_id": "ChIJvQz5TjvKvJURh47oiC6Bs6A",     
     "types": [                                     
       "locality",                                   
       "political"                                   
     ]                                               
   }                                                 
 ],                                                 
 "status": "OK"                                     
 }                                                 

entonces..si quisieramos imprimir solo la direccion formateada, la latitud y la longitud hariamos esto:

let results = response.data.results[0];
    let formatted_address = results.formatted_address;

    let lat = results.geometry.location.lat;
    let lng = results.geometry.location.lng;

    console.log(`Direccion: ${formatted_address}`);
 
console.log(`Longitud: ${lng}`);
 
console.log(`Latitud: ${lat}`);



///////////////////////// refactorizando el codigo//////////////////////////////////

vamos a crear una funcion getLugar para que nos devuelva un objeto con las propiedades
direccion,latitud y longitud. Y lo escribiremos en un archivo aparte (lugar/lugar.app) dentro de un carpeta llamada lugar.

lugar.js:


const axios=require('axios');



const getLugar = async (direccion) => {

   let addressEncoded = encodeURI(direccion);
   let apiKey = "AIzaSyBlRKjSjinm507yd_qWAjvzojhWND7Ip-w";

   let resp = await axios.get(`https://maps.googleapis.com/maps/api/geocode/json?address=${addressEncoded}&key=${apiKey}`);

   if(resp.data.status === "ZERO_RESULTS"){
      throw new Error("No se encontraron resultados");
   }
 
   let results = resp.data.results[0];
   return {
     direccion: results.formatted_address,
     longitud:results.geometry.location.lng,
     latitud:results.geometry.location.lat
   }
 
}
   
module.exports = {
  getLugar
}


y en app.js

const argv=require('yargs').options(
{
   direccion:{
alias:'d',
demand:true,
desc: 'direccion a traer el clima'
}
}).
argv;

const { getLugar } = require('./lugar/lugar.js');

getLugar(argv.direccion)
.then(resp=>{
  console.log(resp)
}).catch(e=>console.log(e));




curso node crear release del proyecto

vamos a crear un tag desde la carpeta en la consola

git tag -a v1.0 -m "Primera version"

listamos los tags

git tag

veremos que hay uno solo

v1.0

y luego pusheamos

git push --tags

luego vamos a nuestra pagina de github y hacemos click en la cabecera que dice "release"
vamos a la pestaña de Tags y ahi clickeamos en "crear release"

le ponemos un titulo, una descripcion y click en el boton de publicar.

nos quedaria algo asi

un Release es un Tag con una descripcion.

entonces desde aqui se puede hacer click para descargar facilmente todo el codigo fuente de la aplicacion

wordress creando un plugin para wordpress

la razon principal para escribir un plugin es separar tu codigo del codigo core de wordpress.
Si algo sale mal el resto del sitio seguira , funcionando.

Una alternativa para modificar las funciones de wordpress es editar el archivo
wp-includes/functions.php o functions.php que es parte de un theme. Sin embargo esto no es recomendable debido a las constantes actualizaciones de wordpress que borraran las modificaciones que le hagas a su archivo functions.php

Los plugind interactuan con el core de wordpress atraves de hooks,
existen 2 tipos de hooks:
1-action hooks , para agregar y/o eliminar funciones
2-filter hooks, para modificar datos producidos por funciones

para crear y activar un plugin nuestro, creamos el archivo php dentro de la carpeta wp-content/plugins
luego en el admin de wordpress, vamos al menu de PLugins, lo ubicamos y activamos.

Ejemplo de action hook, para agregar un bloque de texto al final del footer y lo saca si es domingo (Sunday)

<?php
/*
Plugin Name: Add Text To Footer
Description: Example Plugin Action Hook
*/

// Hook the 'wp_footer' action hook, add the function named 'mfp_Add_Text' to it
add_action("wp_footer", "mfp_Add_Text");

// Hook the 'wp_head' action, run the function named 'mfp_Remove_Text()'
add_action("wp_head", "mfp_Remove_Text");

// Define 'mfp_Add_Text'
function mfp_Add_Text()
{
  echo "<p style='color: black;'>".date("l")."Despues de que el Footer es cargado, mi texto es agrega.do! </p>";
}

// Define the function named 'mfp_Remove_Text()' to remove our previous function from the 'wp_footer' action
function mfp_Remove_Text()
{
  if (date("l") === "Sunday") {
    // Target the 'wp_footer' action, remove the 'mfp_Add_Text' function from it
    remove_action("wp_footer", "mfp_Add_Text");
  }
}


Ejemplo de filter Hook, que reemplaza los espacios en blanco del contenido de un post por asteriscos

<?php
/*
Plugin Name: Replace text space in content post
Description: Example PLugin Filter hook
*/
// Hook the 'the_content' filter hook (content of any post), run the function named 'mfp_Fix_Text_Spacing'
add_filter("the_content", "mfp_Fix_Text_Spacing");

// Automatically correct double spaces from any post
function mfp_Fix_Text_Spacing($the_Post)
{
 $the_New_Post = str_replace(" ", "*", $the_Post);

 return $the_New_Post;
}

wordpress programando en wordpress

worpress tiene 3 componentes principales:

el core, themes y plugins

core: contiene todo el codigo que lo hace funcionar como un CMS
This includes desde the admin backend hasta functions like scheduling posts, password strength checking, lae creation of users and asi. is responsible for the backend of a website and how it operates.

themesare responsible for the front-end and how website’s look and feel. You might want to install and activate pre-built themes or break out of the box completely and go your own way with custom designs.

plugins: proveen funcionalidad extra a wordpress. To make this happen, a plugin may modify the backend and/or the front-end of a website. A plugin that adds a Tweet button for Twitter is a good example. It would probably create a new settings page in the backend admin menu where you could set up some default options for a user’s tweet and it would also add itself to the front-end of a website, most likely displaying under a post.

areas de desarrollo:


themes,plugins, rest apis, core

Plugins

plugins are la esencia de WordPress, transforming it into everything from a forum to a social network, eCommerce platforms and much more with the push of a button. Plugins give you total control over all aspects of the WordPress system, allowing you to modify anything you want. 
The REST API is relatively new and allows you to create true applications based on WordPress. This includes iPhone and Android apps and all sorts of crazy things like TV apps even, if you know some other programming languages.
You can connect to any website and ask it for your latest five posts. But you can do a lot more than that: you can delete users, create users, edit categories and more (which you need to authenticate yourself, of course). This means you can use WordPress as a repository of information and build the front-end and/or the backend using a different system altogether.




linux ubuntu mint actualizar chrome

 desde una terminal: $ sudo apt update $ sudo apt install google-chrome-stable