How to create Nuget Package for .Net Core

Yep! Another article about Nuget package creation. And you know why? It’s a pain in the ass (hou rude words for a shiny morning…).

When I discover Nuget packages I was really enthusiast. It’s look like Composer package. But not really…

You have to manage by hand all the dependencies. And that’s make me angry!

I’m a lazy developer, so how can I make easily a Nuget package, with just only one command line?

Follow me, I show you.

This article is based on my work on the GST.Library that is a .Net Core solution who hold some libraries. I’ve faced the problem of building multi Nuget package from one solution. We need to automate the build of each package and we need something to manage dependencies and cross dependencies of each project.

The solution file organisation:

| GST.Library.sln
|
+---artifacts
| GST.Library.API.REST.1.0.0.nupkg
| GST.Library.API.REST.1.0.0.symbols.nupkg
|
+---src
| +---GST.Library.API.REST
| | | GST.Library.API.REST.nuspec
| | | project.json
| | |
| | +---Annotations
| | \---Pagination
| |
| +---GST.Library.Data
| | | GST.Library.Data.nuspec
| | | project.json
| | |
| | \---Extentions
| |
| +---GST.Library.Helper
| | | GST.Library.Helper.nuspec
| | | project.json
| | |
| | \---Type
| |
| \---GST.Library.StoredProcedureHelper
| | GST.Library.StoredProcedureHelper.nuspec
| \ project.json
|
+---test
\---tools

First of all, we are using Cake (for once cake is not a lie)! Cake is a task runner like Grunt, but made for Windows stuff, like building .Net Core application or C# DSL. What is nice with Cake, that it is cross platform application (you can use it on Linux).

To use Cake, we have to copy two (or one file) from their Github repo https://github.com/cake-build/example.

Take `build.ps1` for running with Powershell or `build.sh` for running with bash.

These two files contains the code for installing Cake, if it’s not, and running the `build.cake` file who will contain all our needed tasks to build Nuget packages.

Now you have to create a `build.cake` file and put this code inside :

#tool "nuget:?package=xunit.runner.console"
//////////////////////////////////////////////////////////////////////
// ARGUMENTS
//////////////////////////////////////////////////////////////////////

var target = Argument("target", "BuildPackages");
var configuration = Argument("configuration", "Release");

//////////////////////////////////////////////////////////////////////
// PREPARATION
//////////////////////////////////////////////////////////////////////

// Define directories.
var artifactsDir  = Directory("./artifacts/");
var rootAbsoluteDir = MakeAbsolute(Directory("./")).FullPath;

//////////////////////////////////////////////////////////////////////
// TASKS
//////////////////////////////////////////////////////////////////////

Task("Clean")
    .Does(() =>
{
    CleanDirectory(artifactsDir);
});

Task("Restore-NuGet-Packages")
    .IsDependentOn("Clean")
    .Does(() =>
{
	DotNetCoreRestore("src");
});

Task("BuildPackages")
    .IsDependentOn("Restore-NuGet-Packages")
    .Does(() =>
{
	var rootAbsoluteDir = "./build/bin";
    var nuGetPackSettings = new NuGetPackSettings
	{
		OutputDirectory = rootAbsoluteDir + @"\artifacts\",
		IncludeReferencedProjects = true,
		Properties = new Dictionary<string, string>
		{
			{ "Configuration", "Release" }
		}
	};

	var settings = new DotNetCoreBuildSettings
     {
         Framework = "netcoreapp1.1",
         Configuration = "Release",
         OutputDirectory = "./artifacts/"
     };

	DotNetCoreBuild("./src/**/project.json", settings);

	var packageSettings = new DotNetCorePackSettings
     {
         Configuration = "Release",
         OutputDirectory = "./artifacts/"
     };

    // For each project that we want to packaged
    DotNetCorePack("./src/GST.Library.API.REST/", packageSettings);
    DotNetCorePack("./src/GST.Library.Data/", packageSettings);
    DotNetCorePack("./src/GST.Library.Helper/", packageSettings);
    DotNetCorePack("./src/GST.Library.StoredProcedureHelper/", packageSettings);
});


//////////////////////////////////////////////////////////////////////
// EXECUTION
//////////////////////////////////////////////////////////////////////

RunTarget(target);

We have one more things to do. That’s the hard part. You have to install Nuget on your system (and add it to your environment variable) or just download the nuget.exe and put it in your project folder.
Now open a Terminal (Powershell console) and write : `nuget spec`
With this command line Nuget will create a ` Package.nuspec` file. This file is the manifest of your package.
Please take time to read the official documentation. But don’t waste time on the dependencies part. Our Cake script will take care to fill-up dependencies for us. We don’t have to do this manually, and that’s the real comfort to use automation.

You can take a look at our github repository https://github.com/GestionSystemesTelecom/gst-library , you will have a real world example. This repository is tie with Appveyor, and every time we push code on that repo, Appveyor compile and push nuget packages to nuget.org.

For the GST.Library, I wanted that each project would be a Nuget package. By putting in each project a “.nuspec” file and using Cake automation, I can easily create multi Nuget package.

Thanks to this blog post to show me the way: https://blog.codeinside.eu/2017/02/13/create-nuget-packages-with-cake/

Publié dans .Net Core

What to Do When Visual Studio Debugger Won’t Attach to Docker

I use Docker since months to developpe ASP.Net Core applications. It’s really something to work with this kind of technologies.

But sometime, a glitch come around and drive you crazy (just a little bit, not more). Docker was running fine and you update your Nuget’s packages (because it’s a good thing to keep ours dependencies up-to-date). And now, Visual Studio start to yell at you that kind of error:

The target process exited without raising a CoreCLR started event. Ensure that the target process is configured to use Microsoft.NETCoreApp 1.0.0 or newer. This may be expected if the target process did not run .NET code.

Like said the book « Don’t Panic! »

Two step to check.

First, in one of your project.json (if you use it), check if in the dependency you have the right syntax for Microsoft.NETCore.App, like below

"Microsoft.NETCore.App": {
"version": "1.1.1",
"type": "platform"
}

Second step, reset to factory defaults your Docker setup, like explain in this post https://dzone.com/articles/what-to-do-when-visual-studio-2017-debugger-wont-a (Yes I’m lazy, I use the same title with no shame ;) ).

If this two steps don’t resolve your problem, now you panic…

Publié dans Visual Studio

Configuration d’un Linux derrière un serveur proxy

Voici comment configurer pleinement un pc sous Linux (Ubuntu, Linux Mint) pour passer à travers un serveur proxy d’entreprise.

Cet article est donc un tutoriel pour configurer Linux pour l’utilisation de cette merveilleuse chose qu’est un serveur proxy d’entreprise.

Pour commencer il vous faut l’adresse IP et le port du serveur proxy. Pour notre article, le serveur proxy aura l’adresse 192.0.0.1, avec le port 8181.

Puis suivez les étapes ci-dessous :
Étape 1 – Configuration du nsswitch
Étape 2 – Configuration WPAD
Étape 3 – Configuration d’APT
Étape 4 – Configuration des variables d’environnements
Étape 5 – Configuration de la commande sudo
Étape 6 – Autres applications

Lire la suite ›

Publié dans Linux, Ubuntu

Symfony2 et jQuery Datatable

Nous avons tous eu, un jour, le besoin d’afficher un tableau de données dans nos pages Web. Quand c’est un tableau de données figées et peu nombreuses, nous le réalisons à la main. Quand elles sont dynamiques, mais toujours peu nombreuses, nos outils de templating, comme Twig, sont amplement suffisants.
Par contre, quand les données sont dynamiques, très nombreuses, qu’il faut gérer une pagination et si en plus ce tableau doit proposer la manipulation de ces données, là ça commence à être vraiment complexe.

Datatable est un plugin pour jQuery qui permet de réaliser simplement des tableaux de données (aussi appelé datagrid) dynamiques et paginables, avec chargement des données asynchrones, qui trie par colonne, filtre des données affichées et/ou filtre côté serveur. Il propose de nombreuses fonctionnalités ce qui le rend vraiment indispensable. Lire la suite ›

Tagués avec : , ,
Publié dans Doctrine, PHP, Symfony2

Plan d’auto-formation à Symfony2 et les concepts associés

Voici un plan d’auto formation à Symfony2 et ses concepts associés. Cet article comporte beaucoup de liens vers différentes documentations qui vous permettrons d’appréhender simplement Symfony2 et le monde de la qualité de code de PHP.

Sommaire

Lire la suite ›

Tagués avec :
Publié dans Non classé, PHP, Symfony2

Extension Doctrine pour la fonction Match Against

Voici un tutorial Symfony2 pour ajouter la fonction Match Againts à Doctrine pour l’utiliser dans vos requêtes DQL.

Le serveur de base de données Mysql gère la fonction Match Againts uniquement avec le moteur MyISAM. Cela est vrais pour les versions inférieur à la 5.6. Dans la version 5.6 cette fonction sera aussi géré par le moteur innoDB. Ce tutorial est donc à adapter si vous bénéficier d’une version 5.6 ou plus.

Lorsque l’on créé une base de données avec Doctrine, il utilise par défaut le moteur innoDB car il gère les relations entre les tables. On va donc être obligé de s’adapter.

Dans ce tutorial, nous cherchons à faire une recherche Full Text sur certain champ d’une entité Fiche. Pour cela nous allons devoir coder un peu.
Dans un premier temps nous allons ajouter la fonction Match Againts à Doctrine (avec ses tests unitaires).
Nous devrons créer ensuite une classe qui servira uniquement à la recherche Full Text. C’est contraignant, mais si vous tenez à réduire le nombre de requête SQL émise par votre application, c’est un mal nécessaire.
Enfin nous ajouterons un écouteur pour synchroniser notre classe d’indexation avec notre fiche.
Lire la suite ›

Tagués avec : , ,
Publié dans Doctrine, PHP, Symfony2

Symfony 2 – Vérifier le role d’un utilisateur dans un Voter

Petit How-To sur comment vérifier si un utilisateur à bien le rôle nécessaire pour effectuer une action dans un Voter.

Avant tout, deux petits lien, l’un vers la documentation des Voter de Symfony 2 et le second sur le fonctionnement du Gestionnaire de décision d’accès (Access Decision Manager) .

Nous verrons ici comment tester si l’utilisateur en cours dispose bien d’un rôle en prenant en compte la hiérarchisation des rôles offert par Symfony 2.

 

Dans un premier temps, il faut ajouter dans le fichier de configuration de l’injection de dépendance, une dépendance au service “security.access.role_hierarchy_voter”.

Votre déclaration de Voter ressemblera à cela :

<service id="security.voter.categorie" class="MyBundle\Security\Authorization\Voter\CategorieVoter" public="false">
   <argument type="service" id="security.access.role_hierarchy_voter" />
   <tag name="security.voter" />
</service>

Dans la classe de votre Voter, il faut bien entendu ajouter un attribut et le constructeur pour récupérer le service.

namespace MyBundle\Security\Authorization\Voter;

use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class CategorieVoter implements VoterInterface
{
    /**
     * @var \Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter
     */
    private $roleVoter;

    public function __construct($roleVoter)
    {
            $this->roleVoter = $roleVoter;
    }
//...
}

L’utilisation est simple.

if($this->roleVoter->vote($token, $token->getUser(), array('ROLE_USER')) === VoterInterface::ACCESS_GRANTED) {
      // l’utilisateur à le role
}

Donc si votre utilisateur à un rôle admin, selon la hiérarchie des rôles, il à aussi un ROLE_USER. Donc le service renverra un VoterInterface::ACCESS_GRANTED !

Tagués avec : , ,
Publié dans PHP, Symfony2

Symfony – Internationalisation des dates pour Twig

Petit How To pour internationaliser l’affichage des dates dans Twig.

Dans le cas où l’on veut afficher des dates du type « 14 février 2032 » vous remarquerez que le filtre « date » avec les paramètres « d F Y » vous affichera la date en anglais.

Pour avoir nos date en français nous allons simplement installer l’extensions Intl de Twig qui ne fait pas partie du package par défaut.

Rendez-vous à l’adresse suivante : http://twig.sensiolabs.org/doc/extensions/intl.html
Sur cette page vous trouverez la commande pour installer l’extension Twig par Composer ou utilisez la commande suivante. Pensez juste à changer le numéro de version pour le dernier.

composer require twig/extensions ~1.2

Une fois ça de fait, vous avez fait la moitié du travail.

Ouvrez le fichier Resources/config/services.xml et ajoutez les lignes suivantes.
Ce paramétrage intègre l’extension à Twig.

    <services>
	< !-- [...] -->
        <service id="twig.extension.intl" class="Twig_Extensions_Extension_Intl">
            <tag name="twig.extension" />
        </service>
    </services>

Pour l’utilisation classique RTFM, et pour aller un peu plus loin (enfin pas trop loin), suivez le guide…

Donc voici quelques exemples :

Pour : 5 janvier

{{ post.published_at|localizeddate('none', 'none', null, null, 'd MMMM') }}

Pour : 5 janvier 1955

{{ post.published_at|localizeddate('none', 'none', null, null, 'd MMMM Y') }}

Pour : lundi 5 janvier 1955

{{ post.published_at|localizeddate('none', 'none', null, null, 'EEEE d MMMM Y') }}

Le formatage des dates se trouve à cette adresse : http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax

Publié dans Symfony2

Symfony 2 – Les Champs de choix booléen avec des radios buttons

Pour représenter un choix booléen (vrai, faux) dans un formulaire en utilisant le composant de formulaire fournit avec Symfony2, il est possible d’utiliser des checkbox.
Mais des fois on veut deux champs radios, pour bien faire comprendre à l’utilisateur qu’il à le choix entre « Oui » et « Non ».

Cependant, si ce champ est obligatoire et que notre utilisateur choisit « Non » il est possible qu’il voit apparaître un joli message d’erreur l’informant que la valeur saisie n’est pas correct.

Je vous donne ici une façon simple et rapide pour avoir un choix booléen avec des radios boutons.

Dans notre exemple, nous allons utiliser l’entité doctrine suivante.
Une entité avec une propriété « estOk » qui peut être soit à « true » soit à « false »

namespace Waldo\SomeBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity() 
 */
class Inscription
{
    /**
     * @ORM\Column(type="boolean")
     */
    protected $estOk;
    //[...]
}

Notre formType va se présenter comme ceci :

namespace Waldo\SomeBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class SomeForm extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
                ->add('estOk', 'choice', array(
                    'label' => 'Êtes vous OK ?',
                    'choices' => array(1 => 'Oui', 0 => 'Non'),
                    'expanded' => true,
                    'multiple' => false,
                    'required' => true
                ));
    }
}

La magie, vient du faite de définir que la valeur de « Oui » est à 1 et non à la constante TRUE. Idem pour « Non », il faut utiliser le chiffre 0 en lieu et place de la constante FALSE.

Dans le cas ou cela ne fonctionne toujours pas, voici la manière forte :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
                ->add('estOk', 'choice', array(
                    'label' => 'Êtes vous OK ?',
                    'choices' => array(1 => 'Oui', 0 => 'Non'),
                    'expanded' => true,
                    'multiple' => false,
                    'required' => true
                ))
                ->addEventListener(\Symfony\Component\Form\FormEvents::PRE_SET_DATA, function (\Symfony\Component\Form\FormEvent $event) {
                    $data = $event->getData();
                    $data->setEstOk( $data->getEstOk() === false ? 0 : 1 );
                    $event->setData($data);
                })
     }
Tagués avec : , ,
Publié dans PHP, Symfony2

KnpMenuBundle le breadcrumb facile !

Dans un article précédent je vous expliquais comment faire un breadcrumb (file d’Ariane) qui fonctionne avec le KnpMenuBundle.
Malheureusement cet article est obsolète (depuis un moment en faite). Les mainteneurs du super KnpMenuBundle ont déprécié la méthode magique getBreadcrumbsArray.

Ne trouvant de solution, j’ai laissé traîner. Mais aujourd’hui je me suis bougé et j’ai pondu le CnertaBreadcrumpBundle !
Comme ça la prochaine fois que j’ai à faire un Breadcrump cela sera une partie de plaisir.

Sur la page github du projet vous trouverez comme l’installer.

Je vais juste vous montrer ici une implémentation plus détaillé que dans la documentation.

Ci-dessou la classe Builder classique au KnpMenuBundle :

namespace WaldoColorfullBundleMenu;

use KnpMenuFactoryInterface;
use SymfonyComponentDependencyInjectionContainerAware;

class Builder extends ContainerAware
{
    public function mainMenu(FactoryInterface $factory, array $options)
    {
        $menu = $factory->createItem('main');

        $menu->addChild('Entrée 1', array('route' => '_route_entre_1'))
                ->addChild('Entrée 1.1', array('route' => '_route_entre_1_1'))
                ->addChild('Entrée 1.1.1', array('route' => '_route_entre_1_1_1'));

        $menu->addChild('Entrée 2', array('route' => '_route_entre_1'))
                ->addChild('Entrée 2.1', array('route' => '_route_entre_2_1'))
                ->addChild('Entrée 2.1.1', array('route' => '_route_entre_2_1_1'));

        return $menu;
    }
}

Dans cette classe on y trouve uniquement notre menu. Ici pas besoin de hack comme dans l’article précédent. C’est le CnertaBreadcrumbBundle qui fait tout le travail.

Maintenant pour l’utiliser dans Twig, rien de plus simple :

{{ cnerta_breadcrumb_render('WaldoColorfullBundle:Builder:mainMenu') }}

C’est tout. Il vous suffit d’appeler le Helper “cnerta_breadcrumb_render” et de lui donner le chemin de votre menu. Comme avec le KnpMenuBundle. Trop facile ?

Voici une implémentation un peu plus poussée, dans le cas où l’on veux customiser directement dans son template le rendu.

{% set currentItem = cnerta_breadcrumb_get('WaldoColorfullBundle:Builder:mainMenu') %}

{% for item in currentItem %}
    {% if loop.index != 1 %}
        {% if loop.index > 2 %} > {% endif %}
        {% if not loop.last %}<a href="{{ item.uri }}">{{ item.label }}</a>
        {% else %}<span>{{ item.label }}</span>{% endif %}
    {% endif %}
{% endfor %}

Cependant, si vous voulez faire les chose bien et créer un template à part uniquement pour le breadcrump, c’est possible. Il suffit d’utiliser le helper “cnerta_breadcrumb_render” et de lui passer un nom de template (comme pour le KnpMenuBundle).

{{ cnerta_breadcrumb_render('WaldoColorfullBundle:Builder:mainMenu', {'template': 'MyWonderfullBundle:Breadcrumb:myBreadcrumb.html.twig'}) }}

Le code et l’architecture de ce bundle se base énormément sur le travail fait sur le KnpLabs.
Ce bundle n’est pas parfait et doit souffrir de bugs (inconnus à ce jour). Mais voila, il fait ce qui lui est demandé et c’est déjà pas mal !

Publié dans PHP, Symfony2