Emre.xyz

@delirehberi thoughts

Composer is an installer and a package management tool. So please stop writing build scripts for Composer, building anything inside your package folder.

Last few days, I try to deploy a Symfony project with Nixops to Google Cloud. I found composer2nix package after some research.

Composer2nix is a nix-expression builder. It parses composer.lock file and generates nix expressions for every composer packages independently. After that you can use generated files in your deployment file like that:

  pkgs = import <nixpkgs>{};
  my_app = import /var/www/app/source{
    inherit pkgs;
  };

Nix builds your application and system when you run nixops deploy.

But NixOps generates a hash folder and installs your package inside this stateless and readonly folder. After that, it makes relations all required packages and your project.

composer2nix generated expression works the same way, e.g. your composer.lock file if had thefidry/alice-data-fixtures package. composer2nix generates expression like that:

"theofidry/alice-data-fixtures" = {
      targetDir = "";
      src = composerEnv.buildZipPackage {
        name = "theofidry-alice-data-fixtures-79913820cf6965cd6ea204cc5882079486f8262e";
        src = fetchurl {
          url = https://api.github.com/repos/theofidry/AliceDataFixtures/zipball/79913820cf6965cd6ea204cc5882079486f8262e;
          sha256 = "108862vlq2j10x69h5i4f4vqh63rfizvkc5kl57ymssk79ajifz2";
        };
      };
    };

Nix uses this expression for fetching wanted package and version in the given URL, and it fetches only once if version not changed in composer.lock file.

So, as you have seen, there is no need for composer install. After the package installation process, we need the dumping autoload.php file. Nix makes that and runs composer install for checking everything is ok.

This roughly explains how composer2nix works and how to build your PHP project with nix.

But I faced a problem when I run nixops deploy command. Seems a package want to modify a file in vendor/ocramius/package-versions/src/PackageVersions/Versions.php.

I said at below, nix independently install packages in separated read-only folders. Ok. What can I do? I created an issue on the GitHub. Ocramius gently responded it and said it works if I disable running composer scripts with --no-scripts parameter. Ok, problem solved for now. But I have many scripts like assets:install or cache:clear

Now, I must manually clear caches all of the backends.

Someone should be saying “Why did you use this package and not another package?” Sorry guys, it is not about me, Sylius depends on these packages.

I decided to write this blog. Forget the Nix. It is not only about nix deployment.

I want to ask some questions to PHP package developers.

Why you are building something after package install inside the package folder. Composer not for that.

It is not only about composer scripts. Why do you modify files inside your package folder? Why vendor/<package> is not stateless?

Please don't do that. Don't touch your package folder after install.

ps: if you curios about our conversation with @ocramius about this situation, you can read from github issue

#composer #nix #php #symfony #sylius #en #nixops #composer2nix

Nixos is a Linux distro working in nix ecosystem.

NixOS is a GNU/Linux distribution that aims to improve the state of the art in system configuration management.

You need to create an instance with the configuration at the below:

  • doesn't matter which server.
  • doesn't matter which location.
  • in the server type option, select iso library and find Nixos 18.x nixos.18.x)
  • doesn't matter server size but at least we need 1GiB ram.
  • doesn't matter all of the other options.

After you deploy the server, you wait until complete server initialization.

Go to the products page and click your server name. You should see view console icon right top of the server management page. Click it and connect the terminal.

Possibly you would face some keyboard layout problems after connecting the terminal from browser. Don't get stuck that problem. We need only copy/paste initial configuration.

Vultr machines have the legacy boot option. Firstly we need to create disk partitions.

We need to know the device name for creating a partition. You can find run fdisk -l command. My device name is /dev/vda

Create an MBR partition table.

parted /dev/vda -- mklabel msdos

Add root partition

parted /dev/vda -- mkpart primary 1MiB -8GiB

And, add a swap partition

parted /dev/sda -- mkpart primary linux-swap -8GiB 100%

After that, you need to make formatting configuration.

For initializing ext4 format for the root partition.

mkfs.ext4 -L nixos /dev/vda1

For creating swap partition run mkswap.

mkswap -L swap /dev/vda2

Before installation, you need to make some little configurations. Mounting nix disk and activation swap area.

Mount nixos iso to /mnt folder.

mount /dev/disk/by-label/nixos /mnt

Activate swap area.

swapon /dev/vda2

And now we can generate the initial config.

nixos-generate-config --root /mnt

This command generates all initial disk and device configuration for you.

After creating the initial configuration completed, you need to change a few configurations. At first, you need to set boot.loader.grub.device option.

Open /mnt/etc/nixos/configuration.nix file with your favorite editor vim or nano.

Find that option and set as boot.loader.grub.device = "/dev/vda"; and enable the grub with this option boot.loader.grub.enable = true;

At the last, you need to enable OpenSSH service for connecting to your server with ssh after installation. And you need to add firewall access to 22 port.

For that, you can add that options your configuration file.

services.openssh.enable = true;
services.openssh.permitRootLogin = "yes";
networking.firewall.allowedTCPPorts=[ 22 ];

Ok. Now you can save and exit the file, and install your Nixos.

nixos-install

It asks to you for root password after you run command.

If everything went well, you should remove installation media from machine and reboot. Go to your Vultr server manage page and remove iso from settings->custom iso section. The server automatically rebooted after that.

Congrats. You can now connect your Nixos server over ssh.

#nix #nixos #vultr #howto #en

I don't know it is possible to enable vim mode, in bash before. I learned today and this feature is awesome.

You can enable vim mode in the bash with only change a parameter in your .bashrc file, like that.

set -o vi

That's it. You can use bash with vim strokes.

#tips #vim #en #bash

You can get file path in vim with % (percent) symbol. Sometimes you need to run a command with the current file path, for example git add filepath or sh filepath.

You can add the current file to git with this command in vim:

:!git add %

or you can run any file with this command:

:!%:p

For example, you write a bash script and saved it. But you don't want to close vim or you don't want to go to another terminal screen. Just you need to write :!%:p and vim run the file for you.

#tips #en #vim #git

When you develop an API client with PHP, you would need data mapper for mapping data from API to an object.

For example, you have requested an API endpoint and you get a response like that:

{
  "user": {
    "username": "delirehberi",
    "bio": "carpenter"
  }
}

And you have a User class

<?php
class User{ 
    protected $username; 
    protected $fullname; 
    protected $bio;
      /**
     * @return mixed
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * @param mixed $username
     *
     * @return User
     */
    public function setUsername($username)
    {
        $this->username = $username;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getFullname()
    {
        return $this->fullname;
    }

    /**
     * @param mixed $fullname
     *
     * @return User
     */
    public function setFullname($fullname)
    {
        $this->fullname = $fullname;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getBio()
    {
        return $this->bio;
    }

    /**
     * @param mixed $bio
     *
     * @return User
     */
    public function setBio($bio)
    {
        $this->bio = $bio;

        return $this;
    }
}

You need to map JSON response to the PHP object. But how?

You will need to know how to use ReflectionClass, PropertyAccess, AnnotationReader.

How do you map class properties to API response fields and returns an object?

At first, you need to decode JSON string to PHP array or object.

$result = json_decode($response, true);

After that, create a Reflection class;

$reflectionObj = new \ReflectionClass(User::class);

Now you can access all properties

$properties = $reflectionObj->getProperties();

You don't need to know your User Class has which properties anymore.

Now, we need PropertyAccessor for manipulating our User object.

$propertyAccessor = PropertyAccess::createPropertyAccessor();

How can manipulate an object property with PropertyAccess object?

$propertyAccessor->setValue(
                    $userObject,
                    $property->getName(), //eg: username
                    $value //eg: emre
                );

OK, we know how to access the property of an object and how to manipulate another object properties.

Now we can start writing our data mapper.

Create an annotation class to configure properties to json values.

use Doctrine\Common\Annotations\Annotation;

/**
 * Class DataMapper.
 *
 * @Annotation
 * @Annotation\Target({"PROPERTY"})
 */
class DataMapper
{
    public $json_field;
}

We will use this object to define a JSON field equal to an object property. We can update our User class property annotations like that:

 /**
     * @var
     * @DataMapper(json_field="username")
     */
    protected $username;
    /**
     * @var
     * @DataMapper(json_field="full_name")
     */
    protected $fullname;
    /**
     * @var
     * @DataMapper(json_field="bio")
     */
    protected $bio;

note: don't forget to add DataMapper class to the header.

We are ready for writing data mapping logic.

  • Create an annotation reader object
  • Create property accessor
  • Create a new empty object (eg: User)
  • Create a reflection object for reach properties
  • Get object properties from reflection object
  • Foreach to properties
    • read property annotation for DataMapper annotation
    • get json_field value from annotation
    • access data from JSON with json_field value
    • set property of a new object with data
  • return new filled object :)
$reader = new AnnotationReader();
$propertyAccessor = PropertyAccess::createPropertyAccessor();
$user = new User();
$reflectionObj = new \ReflectionClass(User::class);
$properties = $reflectionObj->getProperties();
foreach ($properties as $key => $property) {
  $propertyAnnotation = $reader->getPropertyAnnotation($property, DataMapper::class);
  $json_field = $propertyAnnotation->json_field;
  if(!$json_field) continue;
  $value = $result[$json_field];
  $propertyAccessor->setValue(
                    $user,
                    $property->getName(),
                    $value
                );
}

var_dump($user);

Congrats, you can write as a function and use in your project.

#php #reflection #datamapper #annotation #annotationreader #doctrine #symfony

You can run the same command in all active Tmux panes at the same time.

You need to activate command mode in Tmux with Ctrl+B keys and update synchronize-panes setting to on.

:setw synchronize-panes on

To disable it, set as off.

:setw synchronize-panes off

You can toggle synchronize-panes setting without use on-off parameters.

:setw synchronize-panes

#tmux #tips

Sometimes you get an error like that:

container extension liip_imagine not registered

You double-checked all configurations and you are absolutely sure nothing is wrong.

But code not works, why?

Because Php can't convert i to I if os language is not en. Your code searches Liipİmagine and can't find that. Change os's lang code to en_US.UTF-8 for fix that.

Or add this line to .bashrc or .profile file.

export LANG=en_US.UTF-8

bb.

#errors #php #debug #en

Today, we adopt a 3 legged cat for the office. Its name is Rosalind. We are working on some science projects. We gave its name from Rosalind Franklin.

Rosalind Franklin is the owner of the Photo 51 of DNA if you don't hear before. Photo 51 is a milestone for biology. You can read about that in Wikipedia if you are curious.

Rosalind :)

View this post on Instagram

Ofisimizin gülü #rosalind :) ziyarete bekleriz.

A post shared by emre ッ (@delirehberi) on

#cat #office #en

Hi, kats;

I want to talk about my morning routine. I try to keep this routine for 5 weeks and I want to stuck with this routine.

I wake up at approximately 06:00 am every morning. I try to be as consistent as possible with this because it helps to I stay motivated.

Once I'm up, the first thing I do is wash my face and I feed my cats (Tedi and Turgut). I clean the cat litter if my partner hasn't.

Then I check my emails and take notes if any further subject for looking after.

Sometimes I do a quick breakfast, sometimes we do Turkish style breakfast with my partner if not exists an urgent problem in the office.

Then I'm going to the door out and go to the office. I filter a morning coffee when I arrive in the office.

And the new day, let's start to work out.

-emre

#en #me

This is my blog's new face. I'll write my posts here after this.

I don't think to move my old posts to this blog. You can view my posts from github archive if you need.

Sometimes I may write posts in Turkish, sometimes in English. It would be practice for me I think.

I plan to write a post once in three days.

Anyway, hello world posts should be short.

-emre

#en