Laravel: Cómo crear un Sistema de Referidos

Hoy veremos cómo definir un Sistema de Referidos en Laravel.

Las características que vamos a implementar son:

  • Cada usuario tendrá un código (URL) para obtener referidos
  • Cada usuario podrá ver su lista de referidos

¿Qué es un sistema de referidos?

Se dice que una aplicación incluye un sistema de referidos cuando sus usuarios pueden invitar a otros.

Enlace para obtener referidos

¿Por qué un usuario se tomaría la molestia de invitar a otros?

Generalmente se otorgan recompensas por cada registro conseguido, o por cada acción que realizan los usuarios que han sido referidos.

Por ejemplo:

  • Si invitas a una persona y esta persona paga una membresía, tú obtienes un mes gratis.
  • Si invitas a una persona y esta persona hace una compra, tú obtienes un % del valor de la compra como agradecimiento.
  • Si consigues que 10 personas se registren como tus referidos, recibes $100 como agradecimiento.

En realidad, hay muchas formas de recompensar a un usuario que invita a otros a unirse.

Inclusive:

  • Algunas aplicaciones otorgan beneficios por volumen,
  • o permiten gestionar muchos niveles de referidos (donde no sólo obtienes beneficios de tus referidos directos; también de los referidos por ellos).

En nuestro ejemplo de hoy vamos a establecer las bases para un sistema de referidos.

Los beneficios a otorgar a los usuarios es un tema que podrás implementar tú, dependiendo de las necesidades de tu aplicación o proyecto.

Y si necesitas ayuda, recuerda que el servicio de asesoría podría ser conveniente para ti.

Enlace de referidos

Esta es una captura del proyecto en el cual estoy trabajando:

Enlace para obtener referidos

Para mantener la identidad del sitio a salvo reemplacé el dominio.

Pero la idea es esa:

Brindar a los usuarios una URL que les permita obtener referidos.

A esta URL también se le conoce como "URL de afiliados".

Entonces nuestro primer paso será definir una ruta que respete dicho formato.

Eso lo logramos con esta línea:

Route::get('/r/{referralCode}', 'ReferralController@link')->name('referral.link');

Nota:

  • En este caso es suficiente con una URL para obtener referidos. Sin embargo hay otras formas de plantear esto.
  • Por ejemplo, en vez de tener un parámetro de ruta referralCode una alternativa es tener un parámetro GET ref que active la lógica.
  • Si se usa un parámetro GET, entonces es posible obtener referidos no sólo desde una ruta específica, sino desde cualquier ruta de nuestra aplicación.
  • Esto último se puede lograr haciendo uso de un ReferralMiddleware.

En esta ocasión vamos a mantener las cosas simples.

Recuerda que esta es la base y que puedes continuar agregando características según tus necesidades.

Código para obtener referidos

La idea es que cada usuario tenga su propio código para captar referidos.

Para esto puedes ir al modelo User y definir un método estático que genere un código aleatorio (de 7 caracteres en este caso).

El do while nos permite seguir generando códigos en caso que el resultado ya se encuentre en uso:

public static function getUniqueReferralCode()
{
    do {
        $code = Str::random(7);    
    } while (User::where('referral_code', $code)->exists());

    return $code;
}

Para generar la cadena aleatoria estamos usando el método random de la clase Str de Laravel.

Y en esta ocasión estamos considerando una columna referral_code en nuestra tabla users. No olvides de agregar esta columna en tus migraciones.

Si estás usando el sistema de autenticación que incorpora Laravel, entonces en tu RegisterController vas a tener algo similar a lo siguiente:

protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => Hash::make($data['password']),
        'role' => $data['role'],
        'referral_code' => User::getUniqueReferralCode()
    ]);
}

Y no te preocupes por caracteres extraños:

El método random asigna un número o una letra, que puede estar en mayúsculas o minúsculas.

En mi caso tengo unas clases Factory y Seeder asociadas al modelo User, por lo que he generado fácilmente miles de registros para confirmar ello:

Usuarios de prueba con sus correspondientes código de referidos

Tampoco debes preocuparte de que no hayan códigos únicos suficientes para todos los usuarios.

  • Digamos que tenemos 24 letras. Considerando mayúsculas y minúsculas tendríamos 48 posibles valores.
  • Dado que también aparecen números, del 0 al 9 tenemos 10 posibles valores más.
  • Esto significa que por cada posición tenemos 58 posibles valores.
  • En tan sólo 3 posiciones es posible contar con 58x58x58 códigos únicos. Es decir, se tiene abasto para 195mil 112 usuarios.
  • Imagina cuántas combinaciones son posibles con 7 posiciones, si con 4 posiciones ya tenemos más de 11 millones de combinaciones.

Reglas para captar referidos

Imagina el siguiente escenario:

  • Comparto contigo mi enlace de afiliados. Te interesa el servicio o producto.
  • Luego otra persona se entera de tu interés y comparte contigo su enlace correspondiente.
  • Te registras y te vuelves un usuario asiduo de la plataforma.
  • ¿Quién debería recibir la recompensa por invitarte a registrarte?

Lo más justo es que seas referido del primer usuario que te invitó.

Incluso si no te registras el mismo día, pero lo haces durante los próximos 7 días, sería conveniente que el sistema te considere como referido por la persona que te invitó inicialmente.

Y si no te registras en 7 días y lo haces después de mucho tiempo:

  • Entonces el sistema te consideraría como referido por otra persona (dependiendo de quién te haya compartido su enlace primero, luego de los 7 días).
  • Y si no fue nadie, entonces el campo referred_by (referido por) quedaría vacío.

Éstas son las reglas a considerar para el proyecto que estoy desarrollando.

Tú puedes guiarte del ejemplo que estamos viendo e implementar tu sistema de referidos con las reglas que consideres más convenientes.

En mi tabla users tengo definidos los siguientes campos:

$table->string('referral_code', 7)->unique();

$table->unsignedBigInteger('referred_by')->nullable();
$table->foreign('referred_by')->references('id')->on('users');

Una Cookie para recordar quién te invitó

Teniendo lista nuestra base de datos, es hora de escribir la lógica para la captación de referidos.

Empezamos creando nuestro controlador:

php artisan make:controller ReferralController

Y luego el método que atenderá las visitas a las URLs de invitación:

public function link(Request $request, $referralCode)
{   
    if (!$request->hasCookie('referral')) {
        $cookie = cookie('referral', $referralCode, 60 * 24 * 7);

        return redirect('/')->withCookie($cookie);
    }

    return redirect('/');
}

Este método indica que:

  • Si no hay una cookie llamada referral, creamos una y redirigimos al usuario a la ruta raíz de nuestra aplicación.
  • Y si ya existe una, simplemente redirigimos al usuario sin realizar ninguna acción en especial.

El helper cookie recibe 3 parámetros, en este orden: el nombre de la cookie, el valor que tendrá la cookie, y la duración en minutos.

Consumiendo la Cookie

¿O debería decir "comiendo la galletita"?

A lo que voy es que, si ya tenemos una Cookie con el "referral_code" del usuario que hizo la invitación, lo siguiente es:

Leer el valor de la Cookie durante el registro.

En nuestro método create de RegisterController ahora vamos a tener:

return User::create([
    'name' => $data['name'],
    'email' => $data['email'],
    'password' => Hash::make($data['password']),
    'role' => $data['role'],
    'referral_code' => User::getUniqueReferralCode(),
    'referred_by' => $this->getReferredBy()
]);

Como ves, he definido un método getReferredBy:

private function getReferredBy()
{
    $referralCode = Cookie::get('referral');

    if ($referralCode)
        return User::where('referral_code', $referralCode)->value('id');

    return null;
}

De esta forma:

  • Si hay una cookie y por tanto un $referralCode, devolvemos el id del usuario que hizo la invitación.
  • De caso contrario, devolvemos un valor null.

Por cierto:

Para que esto funcione no olvides indicar en tu modelo User que ambas columnas son $fillable:

protected $fillable = [
    'name', 'email', 'password', 'phone', 'avatar', 'role', 
    'referred_by', 'referral_code' // <--
];

Verificando el funcionamiento

Todo bien hasta aquí pero, ¿realmente funciona?

Tanto como tú, yo espero que funcione a la primera.

Para estar seguros, empecemos mostrando a cada usuario su URL de referidos.

Para esto, en tu vista blade simplemente puedes imprimir esta expresión:

route('referral.link', ['referralCode' => auth()->user()->referral_code])

Ahora voy a darle click.

Y efectivamente, he sido redirigido a la página de inicio del proyecto.

¿Cómo sabemos si la Cookie se creó correctamente?

Si usas Chrome, una primera forma es ir a DevTools y dar clic a la pestaña Application. Debajo de Storage encontraremos Cookies.

Allí puedes verificar también cuándo caduca la Cookie:

Lista de Cookies en la DevTools de Chrome

El valor de la Cookie se encuentra encriptado. Esto lo hace Laravel.

Si gustas puedes deshabilitar la encriptación para la ruta que usamos.

Pero realmente no es necesario, porque Laravel sí puede leer el valor de la Cookie.

Si no me crees, simplemente define una ruta /cookie que imprima el valor de la Cookie llamada referral:

Route::get('/cookie', function () {
    return Cookie::get('referral');
});

Y mira que funciona muy bien:

Verificar el valor de una Cookie a través de una ruta

Ahora sí la prueba de fuego ?.

Vamos a registrar un usuario nuevo ...


Y unos segundos después:

Usuario registrado como referido

Ya tenemos nuestro usuario registrado como referido.

Listar referidos

Tenemos una clave foránea en la tabla de users que hace referencia a la misma tabla.

Es interesante.

Pero la cosa no queda allí. También es posible definir relaciones de un modelo consigo mismo.

De hecho es un tema que ya he tratado anteriormente en el canal. Si te interesa, puedes ver el video haciendo clic aquí.

Para nuestro caso vamos a tener 2 métodos:

public function referredBy()
{
    return $this->belongsTo(User::class, 'referred_by');
}

public function referrals()
{
    return $this->hasMany(User::class, 'referred_by');
}

Entonces, si tenemos un usuario $u:

  • Con $u->referredBy podemos acceder al usuario que lo ha referido.
  • Y con $u->referrals podemos acceder a la lista de usuarios referidos por $u.

De hecho acabo de comprobar que esto funcione bien a través de php artisan tinker.

Te invito a hacer lo mismo.

Extra: Botón para copiar enlace

Copiar un texto es muy sencillo. Sobretodo si se encuentra dentro de una caja de texto.

Basta con seleccionar el contenido con doble clic y luego presionar Ctrl + V.

Sin embargo, si deseas facilitar aún más la vida a tus usuarios, puedes agregar un botón "Copiar":

Copiar al portapapeles con un clic

Para esto simplemente define un id para el input y define un evento onclick sobre el botón.

Si usas Bootstrap, tu vista se verá muy similar a la siguiente:

<div class="input-group">
    <input type="text" class="form-control" id="referralLink" readonly value="{{ $referralLink }}">

    <div class="input-group-append">
        <button class="btn btn-sm btn-primary" onclick="copyReferralLink()">
            <i class="fa fa-copy"></i> Copy
        </button>
    </div>
</div>

Cuando el usuario presione el botón, se llamará a la función copyReferralLink:

function copyReferralLink() {
    var input = document.getElementById("referralLink");

    // Select the input
    input.select();
    // For mobile devices
    input.setSelectionRange(0, 99999); 

    // Copy the text inside the input
    document.execCommand("copy");

    // Confirmed copied text
    alert("Your referral link has been copied: " + input.value);
}

Con este código:

  • Obtenemos una referencia del input que contiene la URL.
  • Seleccionamos su contenido.
  • Ejecutamos el comando copy.
  • Y por último mostramos un mensaje de confirmación.

Puedes continuar adaptándolo a tus necesidades ?

Conclusión

Como ves, definir un sistema de referidos no es nada del otro mundo.

Si por algún motivo no te ha funcionado a la primera, recuerda que puedes eliminar las Cookies de tu navegador mientras haces pruebas.

Incluso puedes borrar Cookies con código Laravel (usando el método forget).

Si tienes alguna dificultad puedes dejar un comentario aquí debajo. O si necesitas ayuda más directa puedes solicitar asesoría.

# laravel # cookies

Logo de Programación y más

Comparte este post si te fue de ayuda 🙂.

Regístrate

Accede a todos los cursos, y resuelve todas tus dudas.

Cursos Recomendados

Imagen para el curso Aprende Laravel

Aprende Laravel

Aprende Laravel desde cero y desarrolla aplicaciones web reales, en tiempo récord, de la mano de Laravel.

Iniciar curso
Imagen para el curso Laravel Upgrade

Laravel Upgrade

Actualiza tus proyectos desde cualquier versión hasta la última versión estable de Laravel.

Iniciar curso
Imagen para el curso Laravel y Vue

Laravel y Vue

Desarrollemos un Messenger! Aprende sobre Channels, Queues, Vuex, JWT, Sesiones, BootstrapVue y mucho más.

Iniciar curso

Espera un momento ...

¿Te gustaría llevar mi curso de Laravel, gratis?

Sólo debes ingresar tus datos: