Upload – download files

per salvare un file inviato tramite form:

$req->validate([
'file' => 'required|mimes:csv,txt,xlx,xls,pdf,jpg,jpeg|max:2048'
]);
$filePath = $req->file('file')->storeAs('uploads', $fileName, 'public');

il file viene caricato nella cartella:

\storage\app\public\uploads

come definito nel file di configurazione:

\config\filesystems.php

per rendere disponibile il file per il download:

php artisan storage:link

crea un link da public/storage a storage/app/public

come configurato nella sezione links di filesystems.php

il link al file caricato si può generare con:

echo asset('storage/file.txt');

o generare il file come risposta nel controller:

use Illuminate\Support\Facades\Storage;
return Storage::download('file.jpg', $name, $headers);

in questo caso specificando il “nome file” che lo maschera, o forzando diversi headers

Laravel Queue

php artisan queue:table

crea la migration per creare la tabella jobs.

Creare il job worker:

php artisan make:job ProcessTPlinkSendSms

crea il job dentro app/Jobs/ProcessTPlinkSendSms.php

e lo fai partire con:

php artisan queue:work

Per non dover far partire il worker a mano e tenerlo aperto si può installare supervisor:

sudo apt-get install supervisor

e creiamo la configurazione:

cd /etc/supervisor/conf.d

laravel-queue-emails.conf

e ci incolliamo:

[program:yacatechEmailsQueue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/sites/yacatech/artisan queue:work --queue=emails database --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=root
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/html/sites/yacatech/storage/logs/emails-worker.log
stopwaitsecs=30

E far partire i processi con:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start all
sudo supervirorctl status

Molti a molti

Per creare un legame molti a molti serve innanzitutto una tabella che leghi i due modelli, quindi vai di

MIGRATION

Schema::create('destination_user', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
        $table->foreignId('destination_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
        $table->timestamps();                                    
        $table->softDeletes();              
    });

quindi aggiorniamo i:

MODEL

class User extends Authenticatable
{
    public function destinations()
    {
        return $this->belongsToMany(Destination::class);
    }
}
class Destination extends Model
{
    public function users()
    {
        return $this->belongsToMany(User::class);
    }
}

e ora modifichiamo i blade:

CREATE BLADE

<div class="row mb-3" style="display: none" id="destinations_select">
  <label for="destinations_id" class="col-md-4 col-form-label text-md-right">{{ __('Destinations access') }}</label>

<div class="col-md-6">                       
 <select name="destinations_id" id="destinations_id" multiple class="form-select" >    
   @foreach($array['destinations'] as $destination)                                    
     <option value="{{$destination->id}}"  @if ($array['filter']->input('destinations_id') == $destination->id) selected @endif >
      {{ __($destination->name) }}</option>                                    
   @endforeach
 </select> 
</div>
</div> 

EDIT BLADE

<select name="destinations_id[]" id="destinations_id" multiple class="form-select" >    
 @foreach($array['destinations'] as $destination) 
  <option value="{{$destination->id}}" 
     @foreach ($array['user']->destinations->all() as $us_destination)  
        @if ($destination->id == $us_destination->id) selected @endif 
     @endforeach 
  >{{__($destination->name)}}</option> 
 @endforeach 
</select>

STORE CONTROLLER

$user = new User($input);
$user->push();    

UPDATE CONTROLLER

$user->destinations()->sync($input['destinations_id']);

Inviare mail con laravel

creare il mailable in app/Mail con:

php artisan make:mail preRegistration

in content cambiamo la view con una creata da noi:

return new Content(
view: 'preregistrations.mail',
);

nel costruttore definiamo le variabili da “passare” al blade per personalizzare la mail:

public function __construct(
        public \App\Models\Preregistration $preregistration,            
)
{}

aggiungere la mail al controller:

use App\Mail\preRegistration;
use Illuminate\Support\Facades\Mail;

e per inviare:

Mail::to($preregistration->email)->queue(
    (new \App\Mail\preRegistration($preregistration))->afterCommit()
   );

AfterCommit serve per attendere che il record sia salvato/modificato prima di inviare la mail, in modo da inviarla con i dati aggiornati.

Usare queue per accordare l’invio, o send per inviare instantaneamente ( potrebbe rallentare il caricamento della pagina )

Select multiplo

Serve un select con più opzioni selezionabili?

Lato Blade:

<select id="roles" name="role_id[]" multiple class="form-select">
  @foreach($array['roles'] as $role)
  <option value="{{$role->id}}">{{$role->name}}</option>
  @endforeach
</select>

e nel controller:

$user->roles()->sync($request['role_id']);

Model

Per creare un model

php artisan make:model 'Object' -mcrf

crea model – factory – migration – controller

in routes/web.php agiungere la rotta:

Route::resource('Object', App\Http\Controllers\ObjectController::class);

Localization (traduzioni)

php artisan make:middleware Localization

In resources/lang creare it.json e en.json

In config/app.php cambiare en con it

Aggiungere:

        'available_locales' => [ 
        'English' => 'en',
        'Italiano' => 'it'
    ],

creare la rotta per lo switch di lingua

ogni voce deve avere il file corrispondente in resources\lang

in app\http\middleware\localisation.php aggiungere in handle:

    if (Session::has('locale')) {
        App::setLocale(Session::get('locale'));   
        app()->setLocale(Session::get('locale'));   
    }

In app/http/kernel.php

Aggiungere:

\App\Http\Middleware\Localization::class

Nella sezione

  protected $middlewareGroups = [
        'web' => [
        .....
        \App\Http\Middleware\Localization::class,
        ],

In app\Http\Middleware\Localization.php aggiungere:

use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Session;

Laravel System setup

Composer

Installare composer, seguendo le istruzioni qui: https://getcomposer.org/download/

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"

scarica il file composer-setup.php

php composer-setup.php 

esegue l’installazione, creando il file composer.phar

sudo mv composer.phar /usr/local/bin/composer 

rende disponibile composer in tutto il sistema

sudo apt install composer

Database

impostare un utente e database per l’applicazione

sudo mysql -u root 
mysql> CREATE USER 'laraTest_user'@'%' IDENTIFIED WITH mysql_native_password BY 'laraTest_pass'; 
mysql> CREATE DATABASE laraTest;
mysql> GRANT ALL PRIVILEGES ON laraTest.* TO 'laraTest_user'@'%';
mysql> quit;

Apache

dentro /etc/apache2/sites-available creare il file di configurazione e linkarlo poi in sites-enabled prima di riavviare il servizio. All’interno la configurazione dovrebbe essere circa:

ServerName www.test.progetto.local
Options Indexes FollowSymLinks
DocumentRoot /var/www/html/progetto/public/
<Directory "/var/www/html/progetto/public/">
    Order Allow,Deny
    Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error_progetto.log
CustomLog ${APACHE_LOG_DIR}/access_progetto.log combined

In /etc/apache2/mods-enabled: sudo ln -s ../mods-available/rewrite.load

_ impostare i diritti su alcune cartelle del progetto:

chmod 777 storage/logs
chmod 777 storage/framework/sessions
chmod 777 storage/framework/views
chmod 777 bootstrap/cache

il resto della cartella di progetto dovrebbe essere:
_ del gruppo www-data
_ dell’utente “developer”
_ chmod 775

PHP

nel file php.ini de-commentare:

extension=curl
extension=fileinfo
extension=imap
extension=openssl
extension=pdo_mysql

Other requirements

sudo apt install nodejs
sudo apt install npm


Molti a molti

USER -> ROLES

MODEL:

USER

public function roles()
{
    return $this->belongsToMany(Role::class);
}

ROLE

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

MIGRATION

public function up()
{
Schema::create('role_user', function (Blueprint $table) {
      $table->id();
      $table->bigInteger('user_id')->unsigned();
      $table->bigInteger('role_id')->unsigned();
      $table->timestamps();
      $table->foreign('user_id')->references('id')->on('users');
      $table->foreign('role_id')->references('id')->on('roles');
    });
}

USER CONTROLLER

class UserController extends Controller
{
public function __construct() {
$this->middleware(‘auth’);
}

public function index()
{
    $users = User::all();       
    return view('users.index', compact('users'));
}

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
public function create()
{
     $roles = Role::all();
     return view('users.create',compact('roles'));
}

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    $user = new User($request->all());
    $user->save();        
    $user->roles()->sync($request['role_id']);         

    return redirect(route('users.index'));
}

/**
 * Show the form for editing the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function edit($id)
{
    $user = User::find($id); 
    $roles = Role::all();

    $array = array(
                'user'=> $user,
                'roles'=> $roles,                    
                );

    return view('users.edit',compact('array'));

}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function update(Request $request, $id)
{
    $user = User::find($id);         
    $input = $request->all();

    $user->update($input);

    $user->roles()->sync($input['role_id']);        
    //prende i role_id dalla request, e dice al model di User di sincronizzare la tabella pivot con i dati delle request

    return redirect(route('users.index'));
}



}

BLADE

{{ __(‘Role’) }}

        <div class="col-md-6">
            <select name="role_id[]" multiple>

                @foreach($array['roles'] as $v)
                <option value="{{$v->id}}" 

                        @foreach( $array['user']->roles->all() as $role)                        
                    @if ($v->id == $role->id)
                    selected
                    @endif
                    @endforeach   
                    >

                    {{$v->name}}

                </option>
                @endforeach
            </select>
        </div>

Has – With – WhereHas

da questo post: https://stackoverflow.com/questions/30231862/laravel-eloquent-has-with-wherehas-what-do-they-mean

With

Carica l’oggetto, completo dell’oggetto agganciato via chiave esterna.
User > hasMany > Post

$users = User::with('posts')->get();
foreach($users as $user){
    $users->posts; // i post dell'utente sono già stati caricati con la query iniziale
}

Has

Per filtrare gli oggetti che hanno una certa relazione.

$users = User::has('posts')->get();
// solo utenti che hanno almeno un post

WhereHas

Per filtrare oggetti, in base alla proprietà di un oggetto referenziato.

$users = User::whereHas('posts', function($q){
    $q->where('created_at', '>=', '2015-01-01 00:00:00');
})->get();
// solo utenti che hanno post creati dopo il 2015