Archivo de la categoría: Symfony

Docker

Comandos útiles:

// ingresar al contenedor del servidor
$ docker-compose exec NOMBRE_CONTENEDOR_SERVIDOR bash
//Ingresar al contenedor del servidor de BD
$ docker-compose exec NOMBRE_CONTENEDOR_DB mysql -u USUARIO --password=CONTRASEÑA

API PLATFORM

Conceptos

Serialization: la información es transformada de un objeto a un formato distinto ej: JSON

Normalization: la información es transformada de un objeto a un array. Este es un paso intermedio entre la serialización a la deserializacion. Ej: objeto -> (normalizado) Array -> Json.
En API PLATFORM, la normalization (normalizationContext) es cuando se lee información y la denormalization (denormalizationContext) cuando se escribe información

Deserilaization: la información es transformada de un formato distinto ej: JSON a un objeto

Instalacion en Symfony:

$ composer require api
$ composer require jwt-auth
$ mkdir var/jwt
$ echo "thepass" | openssl genpkey -out var/jwt/private.pem -pass stdin -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096
$  echo "thepass" | openssl pkey -in var/jwt/private.pem -passin stdin -out var/jwt/public.pem -pubout
$ setfacl -R -m u:www-data:rX -m u:"$(whoami)":rwX var/jwt
$ setfacl -dR -m u:www-data:rX -m u:"$(whoami)":rwX var/jwt

JWT: https://api-platform.com/docs/core/jwt/#jwt-authentication

Test

$ composer require --dev test-pack http-client justinrainbow/json-schema
// modificar phpunit.xml.dist con la versión de PHP unit que necesitamos
$ php bin/phpunit
// En env.test agregar la base de datos que vamos a usar para test
// DATABASE_URL=mysql://root:thepass@127.0.0.1:3306/database_test?serverVersion=5.7
$ php bin/console doctrine:create:database --env=dev
$ composer require --dev alice
$ composer require logger

Configuraciones de un recurso:


/**
 * @ApiResource(
 *     collectionOperations={"get", "post"}, -> add/remove operaciones de coleccion
 *     itemOperations={
 *         "get" = {"path"= "/description_de_producto/{id}"}, -> cambia la url para ese endpoint 
 *         "put", 
 *         "delete"} 
 *     ) 
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Productos
{


/**
 * @ApiResource(
 *     collectionOperations={"get", "post"}, -> add/remove operaciones de coleccion
 *     itemOperations={"get", "put", "delete"} -> add/remove operaciones de item
 *     shortName="Product" -> cambia el nombre de la url que por defecto toma el de la entidad
 *     ) 
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Productos
{


Normalizer / DeNormalizer

/**
 * @ApiResource(
 *     collectionOperations={"get", "post"},
 *     itemOperations={"get", "put", "delete"},
 *     normalizationContext={ -> cuando se lee información de la API
 *         "groups"={"products:read"}, "swagger_definition_name"="Read",
 *     },
 *     denormalizationContext={ -> cuando se escribe información de la API
 *         "groups"={"products:write"}, "swagger_definition_name"="Write",
 *     },
 *     ) 
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Productos
{

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"products:read", "products:write"})
     */
    private $title;

Serialization name

class Productos
{
    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"products:read", "products:write"})
     * @SerializedName("description")
     */
     public function setTextDescription() {

Filters

use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\BooleanFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\RangeFilter;
use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
/**
 * @ApiResource(
 *     collectionOperations={"get", "post"},
 *     itemOperations={"get", "put", "delete"},
 *     attributes={
 *         "pagination_items_per_page"=10 -> paginación
 *         "formats"={"jsonld", "json", "html", "jsonhal", "csv"={"text/csv"}} -> formatos que acepta la API, hay q activarlos en el config de la API
 *     }
 *     ) 
 * @ApiFilter(BooleanFilter::class, properties={"isPublished"})
 * @ApiFilter(SearchFilter::class, properties={"title": "partial"}) -> partial, exact, start, end, word_start
 * @ApiFilter(RangeFilter::class, properties={"price"})
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 * @ApiFilter(PropertyFilter::class) -> permite devolver solo los campos que queremos: ?properties[]=title&properties[]=shortDescription
 */

class Productos
{


Seguridad en end points

/**
 * @ApiResource(
 *     collectionOperations={
 *          "get",
 *          "post"={"security"="is_granted('ROLE_USER')"}
 *          "put"={
 *              "security"="is_granted('ROLE_USER') and object.getUser() == user",
 *              "security"="Only the creator can edit a cheese listing"
 *              },
 *     },
 *     ) 
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Productos
{


Generar rutas en base a IRIs:

public function login(IriConverterInterface $iriConverter)
    {
        return new Response(null, 204, [
            'Location' => $iriConverter->getIriFromItem($this->getUser())
        ]);
    }

Deshabilitar docs en producción:

$ touch config/packages/prod/api_platform.yml
//Dentro de este archivo agregar
api_platform:
    enable_docs: false
    enable_entrypoint: false

Symfony Cheat Sheet

Response:

Devolver un Archivo PDF

use Symfony\Component\HttpFoundation\BinaryFileResponse;
//..
return new BinaryFileResponse('/path/al/archivo.pdf');

JSON Response

use Symfony\Component\HttpFoundation\JsonResponse;
//..
$response = new JsonResponse();
$response->setData(array(
    'data' => 123
));
return $response;

Cache:

Cambiar permisos:

Symfony 2:

$ HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`
$ sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs
$ sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs

#Comandos anteriores en una sola linea
HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`;setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs;setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs;

Symfony 3:

$ HTTPDUSER=`ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`
$ sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX var
$ sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX var

#Comandos anteriores en una sola linea
HTTPDUSER=`ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`;setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX var;setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX var;

Doctrine:

Dump

echo '<pre>';
\Doctrine\Common\Util\Debug::dump($entities);
echo'</pre>';

Controller:

Dump


//$variable = Variable a imprimir
//$this = El controlador
dump($variable, $this);

Twig:

Dump


//variable = Variable a imprimir
//Se puede no pasar una variable e imprime todas las variables que existen en el template
{{ dump(variable)}}

Crear proyecto en Symfony 4
//Opcion 1
$ composer self-update
$ composer create-project symfony/skeleton my_project
//Opcion 2
$ symfony new my_project
$ cd my_project
$ symfony check:req
$ php -S 127.0.0.1:8000 -t public
//Symfony 5 no necesario
$ git init
$ git add .
$ git commit
//Symfony 5 no necesario
$ composer require server
$ composer require annotations
$ composer require twig
$ composer require asset
$ composer require profiler –dev
$ composer require debug
//Descarga el pack ORM
$ composer require orm
//Entonces podemos obviar estos comandos
$ composer require doctrine
//Fin Entonces podemos obviar estos comandos

$ composer require stof/doctrine-extensions-bundle
$ composer require orm-fixtures –dev
$ composer require zenstruck/foundry –dev //permite crear fixtures con factories

$ composer require maker –dev
$ composer require form validator twig-bundle security-csrf annotations
$ composer require nesbot/carbon -> para mostrar fechas al estilo «hace 2 dias»
$ composer require knplabs/knp-time-bundle -> para mostrar fechas al estilo «hace 2 dias»
$ composer require test –dev

Paginación:
$ composer require knplabs/knp-paginator-bundle

Traducciones:
$ composer require symfony/translation

Front End:
$ composer require encore
$ yarn install
$ ./node_modules/.bin/encore dev –watch
//$ ./node_modules/.bin/encore dev-server Esto hace que los archivos se generen en el server lo que hace
//que se generen automaticamente pero sin el efecto secundario de renderizar la pagina sin que esten listo y
//ademas refresca con los cambios
$ yarn add eslint –dev
$ touch .eslintrc.js
Agrega este contenido dentro de .eslintrc.js
module.exports = {
extends: [‘eslint:recommended’],
parserOptions: {
ecmaVersion: 6,
sourceType: ‘module’,
ecmaFeatures: {
jsx: true
}
},
env: {
browser: true,
es6: true,
node: true
},
rules: {
«no-console»: 0,
«no-unused-vars»: 0
}
};
Ir a settings en PHP storm, buscar eslint y habilitarlo

//Validar con eslint el código
$ ./node_modules/.bin/eslint assets/

Inside webpack.connfig.js make this change
//.enableSingleRuntimeChunk()
.disableSingleRuntimeChunk()

Para importar entradas en twig
{{ encore_entry_css_files(‘app’) }}
{{ encore_entry_js_files(‘app’) }}

Twig extensions:

$ composer require twig/extensions
Activar la extension que queremos utlizar en el archivo config/packages/twig_extensions.yml

Doctrine:

$ ./bin/console doctrine:database:create
$ ./bin/console make:entity
$ ./bin/console make:migration  // crea un archivo con las consultas sql para crear las tablas en la base de datos, conviene añadir estos archivos en git
$ ./bin/console doctrine:migrations:migrate // ejecuta el archivo migrations y va iterando entre las versiones de estos archivos
$ ./bin/console doctrine:migration:status

TESTING

composer require –dev phpunit/phpunit symfony/test-pack

FIXTURES
//Fake fixtures
$ composer require zenstruck/foundry –dev
$ symfony make:factory
//Crear fixtures
$ ./bin/console make:fixtures
// Cargar fixtures
$ ./bin/console doctrine:fixtures:load

//Ejecutar una consulta directamente en la base de datos
$ ./bin/console doctrine:query:sql ‘Select * from products’

PHPStorm Y Symfony
1. Instalar Symfony plugin
2. Instalar PHP annotations plugin
3. PHP Toolbox plugin
4. Buscar Symfony plugin y hacer click en el check «Enable plugin for this project»
5. Buscar «composer» y seleccionamos el archivo composer de nuestro proyecto

Symfony Server
$ symfony serve
$ symfony serve -d //correrlo como demon
$ symfony local:serve:stop

Comandos utiles
1. Lista de servicios disponibles


./bin/console debug:autowiring

//Todos los servicios en el contenedor
./bin/console debug:container --show-private

2. Ver la configuracion de un servicio


./bin/console config:dump NOMBRE_DEL_BUNDLE

3. Ver las variables de entorno


./bin/console about

php bin/console debug:container –env-vars

php bin/console debug:container –env-vars -e test

Security

Obenert contraseña encodeada
./bin/console security:encode-password

Crear un voter
./bin/console make:voter

Crear un normalizer:
./bin/console make:serializar:normalizer

Crear un validator
./bin/console make:validator





Easy Admin:

Dump

$  composer require admin