Curso Avanzado de PHP

Curso Avanzado de PHP

Héctor Benitez

Héctor Benitez

Crear un comando para agregar usuarios

31/35

Lectura

Como lo platicamos anteriormente, hasta este momento hemos dejado sin validación nuestra sección para crear usuarios, esto es muy conveniente en este punto porque estamos desarrollando nuestra app, pero no queremos dejar esta sección pública cuando subamos nuestra app a producción.

Vamos a continuar practicando nuestras habilidades y crearemos el comando app:create-user

Creando el comando

Debemos crear una clase nueva que en este caso yo llamaré CreateUserCommand y que debe extender de Symfony\Component\Console\Command\Command, despues de eso, vamos a agregar la propiedad estática $defaultName con el valor ‘app:create-user’; y crearemos los métodos configure y execute, aunque por ahora los dejaremos vacíos.

<<?php
namespace App\Commands;
use App\Models\User;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CreateUserCommand extends Command
{
    protected static $defaultName = 'app:create-user';
    protected function configure()
    {
    	// Aquí va la configuración
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
	// Aquí va el código del comando
    }
}>

Configuración del comando

Ahora que ya tenemos nuestro comando vamos a pasar a agregar la configuración, para esto vamos a indicar que necesitamos un parámetro requerido que será el email del usuario.

<$this->addArgument('email', InputArgument::REQUIRED, 'The email of the user.');>

Ejecución del comando

Una vez que tenemos la configuración, es momento de ejecutar nuestro comando, para esto lo único que vamos a hacer es leer el argumento requerido y de ahi crearemos un usuario con un password default:

<$output->writeln([
        'User Creator',
       '============',
       '',
]);
$user = new User();
$user->email = $input->getArgument('email');
$user->password = password_hash('UnPassMuySeguro', PASSWORD_DEFAULT);
$user->save();
$output->writeln('Done.');>

Registro del comando

Para finalizar, lo único que necesitamos es registrar nuestro comando en el archivo console.php y ya estará listo para ser utilizado por nuestros usuarios.

$application->add(new \App\Commands\CreateUserCommand());

Conclusión

Así se debe ver el archivo final:

<<?php
namespace App\Commands;
use App\Models\User;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CreateUserCommand extends Command
{
    protected static $defaultName = 'app:create-user';
    protected function configure()
    {
        $this
            ->addArgument('email', InputArgument::REQUIRED, 'The email of the user.')
        ;
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln([
            'User Creator',
            '============',
            '',
        ]);
        $user = new User();
        $user->email = $input->getArgument('email');
        $user->password = password_hash('UnPassMuySeguro', PASSWORD_DEFAULT);
        $user->save();
        $output->writeln('Done.');
    }
}

>

¿Ves cuán fácil fue? con todo lo que aprendiste hasta este momento crear comandos será una tarea simple pero a la vez muy util para tus aplicaciones, digamos que los comandos son acciones que solo podrán ser ejecutadas por alguien que tenga acceso de consola a nuestra aplicación, por lo que estas acciones a la vez son muy seguras.

Como paso siguiente y para que sigas practicando, te propongo los siguientes retos:

  • Agrega el parámetro opcional password y úsalo en caso de que el usuario lo ponga, en caso de que no lo encuentres entonces usa el default.

  • Crea en la aplicación una sección para poder cambiar el password dentro del área de administración.

Con lo que sabes hasta ahora, ambas tareas serán muy sencillas para ti y te permitirán reforzar tus conocimientos.

Aportes 7

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Excelente

 public function postUpdateUserAction($request){
        $responseMessage = null;
        $postData = $request->getParsedBody();
        $user = null;
        $userValidator = v::key('password', v::stringType()->notEmpty());
        try {
            $userValidator->assert($postData);
            $postData = $request->getParsedBody();

            $user = User::findOrFail($_SESSION['userId']);
            $user->password = password_hash($postData['password'], PASSWORD_DEFAULT);
            $user->save();

            $responseMessage = 'Updated';
        } catch (\Exception $e) {
            $responseMessage = $e->getMessage();
        }

        return $this->renderHTML('users/edit.twig', [
            'responseMessage' =>$responseMessage,
            'user' => $user
        ]);
    }

Reto 1.

class CreateUserCommand extends Command {
  protected static $defaultName = 'app:create-user';
  protected function configure () {
    $this->addArgument('email', InputArgument::REQUIRED, 'The email of the user.');
    $this->addArgument('password', InputArgument::OPTIONAL, 'The email of the user.');
  }

  protected function execute(InputInterface $input, OutputInterface $output) {
    $output->writeln([
      'User Creator',
      '============',
      '',
    ]);
    $user = new User();
    $user->email = $input->getArgument('email');
    if (!$input->getArgument('password')) {
      $user->password = password_hash('UnPassMuySeguro', PASSWORD_DEFAULT);
    } else {
      $user->password = password_hash($input->getArgument('password'), PASSWORD_DEFAULT);
    }
    $user->save();
    $output->writeln('Done.');
  }
}

Reto 1

Comando

<?php

namespace App\Commands;

use App\Models\User;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class CreateUserCommand extends Command
{

    protected static $defaultName = 'app:create-user';

    protected function execute(InputInterface $input, OutputInterface $output) {
        $output->writeln([
            'User Creator',
            '============',
            '',
        ]);

        $password = ($input->getArgument('pass')) ? $input->getArgument('pass') : User::generatePassword(12);

        $user = new User();
        $user->name = $input->getArgument('name');
        $user->email = $input->getArgument('email');
        $user->password = password_hash($password, PASSWORD_DEFAULT);
        $user->save();

        $output->writeln("Your password: {$password}");
        $output->writeln('Done.');
    }

    protected function configure() {

        $this->addArgument('email', InputArgument::REQUIRED, 'The email of the user.');
        $this->addArgument('name', InputArgument::REQUIRED, 'The name of the user.');
        $this->addArgument('pass', InputArgument::OPTIONAL, 'A password of the user.');
    }
}

Creación de un trait para generar contraseñas

<?php

namespace App\Traits;

trait HasDefaultPassword
{
    public function generatePassword ($length = 8) {
        $_alphaSmall = 'abcdefghijklmnopqrstuvwxyz';
        $_alphaCaps  = strtoupper($_alphaSmall);
        $_numerics   = '1234567890';
        $_specialChars = '`[email protected]#$%^&*()-_=+]}[{;:,<.>/?\'"\|';
        $_container = $_alphaSmall.$_alphaCaps.$_numerics.$_specialChars;
        $password = ''; 

        $password = substr(str_shuffle($_container), 0, $length);

        return $password;
    }
}

Usando el trait en el modelo user

<?php

namespace App\Models; 

use App\Traits\HasDefaultPassword;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{

    use HasDefaultPassword;
    
    protected $table = 'users';
}

El otro reto lo podran ver en el repo en https://github.com/isaacBats/curso-php en la carpeta que se llama project
por que es mucho codigo.
vistas para listar usuarios y editar
controladores: acciones para mostrar los usuarios , mostrar el formulario y modificar
rutas, las rutas que se agregaron para todas las acciones

Reto 1

CreateUserCommand.php

 protected function configure(){
        $this->addArgument('email',InputArgument::REQUIRED, 'The email of the user')
             ->addArgument('pass', InputArgument::OPTIONAL, 'The pass of the user');
    }

   protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln([
            'User Creator',
            '============',
            '',
        ]);
      $user = new User();
      $user->email = $input->getArgument('email');
      $pass_aux = $input->getArgument('pass') ?? "4321";
      $user->password = password_hash($pass_aux, PASSWORD_DEFAULT);
      $user->save();
      $output->writeln('Done.');
      return 0;
   }

Reto 2

public/index.php

....
$map->get('showPass','/users/pass',[
    'App\Controllers\UsersController',
    'getPassword'
]);
$map->post('change','/users/changepass',[
    'App\Controllers\UsersController',
    'changePassword'
]);
....

Controllers/UsersControllers.php

public function getPassword(){
        return $this->renderHTML('users/pass.twig');
    }

public function changePassword($request){
        $responseMessage = '';
        $classMessage = '';
        if($request->getMethod() == "POST"){
            $postData = $request->getParsedBody();

            $dataValidation = Validator::key('password',Validator::stringType()->notEmpty())
                                       ->key('newpass',Validator::stringType()->notEmpty())
                                       ->key('confirmpass',Validator::stringType()->notEmpty());
            try {
                $dataValidation->assert($postData);
                $sessionUserId = $_SESSION['userId'] ?? null;
                $userSearch = User::find($sessionUserId);
                if($userSearch){
                    if(password_verify($postData['password'],$userSearch->password)){
                        if($postData['newpass']==$postData['confirmpass']){
                            $newPass = $userSearch->password_hash($postData['newpass'],PASSWORD_DEFAULT);
                            $userSearch->password = $newPass;
                            $userSearch->save();
                            $responseMessage = 'saved';
                            $classMessage = 'success';
                        }else{
                            $responseMessage = 'Confirm Pass';
                            $classMessage = 'warning';
                        }
                    }else{
                        $responseMessage = 'Check credentials';
                        $classMessage = 'warning';
                    }
                }else{
                    $responseMessage = 'User not Found';
                    $classMessage = 'error';
                }
            }catch (\Exception $e){
                $responseMessage = $e->getMessage();
                $classMessage = 'warning';
            }

        }
        return $this->renderHTML('users/pass.twig',[
           'responseMessage' => $responseMessage,
           'classMessage' => $classMessage
        ]);
    }

views/users/pass.twig

{% extends 'layout.twig' %}
{% block content %}
    {% if responseMessage != '' %}
        <div class="alert alert-{{ classMessage }}">
            {{ responseMessage }}
        </div>
    {% endif %}
    <form action="/users/changepass" method="post">
        <h1>Change Password</h1>
        <label for="">Password</label>
        <input type="text" name="password"><br>
        <label for="">New Pass</label>
        <input type="password" name="newpass"><br>
        <label for="">Confirm Pass</label>
        <input type="password" name="confirmpass"><br>
        <button type="submit">Change</button>
    </form>
{% endblock %}
// index.php
// Router
$map->get('changePassword', '/primer-proyecto-php/changePassword', [
    'App\Controllers\ResetPasswordController',
    'changePassword'
]);
$map->post('resetPassword', '/primer-proyecto-php/resetPassword', [
    'App\Controllers\ResetPasswordController',
    'resetPassword'
]);
// App\Controllers\ResetPasswordController.php
<?php

namespace App\Controllers;

use App\Models\{User};
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Response\RedirectResponse;

class ResetPasswordController extends BaseController{
    public function changePassword(){
        return $this->renderHTML('changePassword.twig');
    }

    public function resetPassword(ServerRequest $request){

        $postData = $request->getParsedBody();

        if (!$postData['password']) {
            return;
        }

        $user = User::where('id', $_SESSION['userId'])->first();
        $user->password = password_hash($postData['password'], PASSWORD_DEFAULT);
        $user->save();

        return new RedirectResponse('/primer-proyecto-php/admin');
    }
}

¿Saben qué cosa si sería interesante y MUY útil hacer con los comandos? Hacer un comando que te genere un template de algún controller.php y lo guarde dentro de la carpeta Controllers pasando el nombre del controlador como parámetro 👀

Con PHP puedes crear y escribir archivo, o incluso copiarlos… así que… creatividad!