Thursday 11 October 2012

Forcing composer to use https connections to Packagist

Been having problems with composer from behind a company firewall. The firewall was blocking us from accessing a particular package.json file from the http://packagist.org website

What was strange though was that it was only blocked over http:// connections and perfectly accessible from https:// connections.

However, I have, after much trial and error and research, found a workaround. It's not a particularly graceful workaround but it takes advantage of the fact that composer does not recursively resolve repository locations and only takes commands from the main project's composer.json configuration.

I realised when reading the documentation on the composer github site that you could disable the default packagist configuration. In addition, of course you can add your own repositories to the composer.json in your project.

So, adding the following to the composer.json solves the problem and I'm able to bypass the blocks put in place by the firewall.

    
    "repositories": [
        {
             "type": "composer", 
             "url": "https://packagist.org" 
        },
        { "packagist": false }
    ]

Of course, this does solve a problem that was only relevant in a particular scenario and probably won't be relevant to the vast majority of people. But if you have a similar situation, hopefully this will help.

Wednesday 6 June 2012

Template update

I got bored with all the black on this blog. So 2009... ;o) Anyway, hope you like the tweaked template. Let me know if you have any comments or if anything is broken that I have not noticed.

Creating a correctly structured Git Repository using Eclipse and EGit

So I've been really getting into Git source control and playing around with it in order to get my head around the differences between Git and SVN (which I have far more experience with).

I love the whole DVCS concept. I have to remind myself often that every copy of the repository is a full copy of the repository. Migrating one of my projects that I was hosting remotely on a local server to a hosted repository at BitBucket became a lot easier once I realised I could just create an empty repository somewhere else and add it as a remote repo and push to it. So cool...

But I digress.

My purpose for writing this post is that I've seen a few people asking (because I was searching for the answer to the same question) about how to import a hosted Git Repository into a new project in Eclipse using eGit. Should be as easy as right-clicking in the workspace in Eclipse and choosing Team --> Import --> project from Git right? Uh.. no.

The problem is that this method, while cloning your project correctly, insists on adding a sub directory under what should be the repository root.... so let's say our repositories are stored by default at /Users/beldougie/git/MyProject. What you'd get is the project being created at /Users/cinh/git/MyProject/MyProject which isn't what we're after. Especially if you're working on something to be distributed. You need it to be structured correctly.

So I've found a solution (I think) in any case. It certainly seems to work for me. For this example, I'm using a private repository hosted at BitBucket and I'm going to set up an imported linked project that uses EGit to manage it. To follow along with this example you will need ssh access to your git repository at BitBucket. I'm not planning to write anything about that step of the process because there's plenty of material available already if you need it. Plus BitBucket's documentation is pretty thorough.

  1. So I'll start by creating a basic, empty repository in BitBucket.
  2. Next we need to create reference to the repository in Eclipse. If you don't already have the Git Repositories view open in Eclipse, open it...
  3. On your BitBucket repository page in your browser, copy your repositories url. Don't worry about the "e;git clone"e; part, we just need to copy the url
  4. Return to Eclipse and in your Git Repositories view, right-click in the open pane and you should see something like

    Click it.
  5. If you've copied the URL correctly from step 3, you will see a dialog appear similar to:

    Click 'Next' and it should connect to the remote repository to get a list of branches.

    Of course, this will be empty at the moment if this is a brand new repository so just go ahead and click next.

    On this last screen, do make sure you enter a tick next to "Import all existing projects after clone finishes". This will save you the following steps if valid projects already exist within your repository.
  6. Click "Finish" and you're done - at least you would be, if you had existing projects within your repository. But if you've been following along with this, you have an empty repository and, therefore you don't have any projects yet. So...

    Right click on your php explorer and click New --> PHP Project (assuming that you want a PHP project of course... it could be any project as far as I know but I haven't tested that.)
  7. Enter a name for your project, Select the option to "Create project at existing location (from existing source)" and enter the directory you cloned your remote repository to.

    Note the warning at the bottom of the dialog. It's really just a notification and shouldn't be a problem.
  8. At this point, just click "Finish" unless you want to configure the project further at this point. You can always go back and do this from the properties later on though, so we're just going to push on and create the project.

    You'll see a new project called "Dummy" (or whatever you called your project) in your workspace.
  9. There's still a problem though. If you right-click on your project and select the team option, you'll see that it still invites you to 'share' your project, or link it to a repository. So click the 'share project' option. In the dialog select Git and click Next

    Make sure you tick the option to "Use or create repository in parent folder of project" and tick select your project in the lower half of the dialog and you should end up with something like
  10. Click Finish and the connection is made and you now have the team functions enabled for your project:
  11. Unfortunately though, there is still a problem (if you're using BitBucket at least) because our remote repository was created without any branches. This is pretty simply fixed though. Because Eclipse has already added .project, .buildpath and .settings directories to the project root, we don't need to add a README file or equivalent (as the Git docs would have you do). Unless you want to of course. It's generally good practice.

    Anyway, I'll leave that up to you. What we're going to do is add a .gitignore file instead.

    I like to share my .project folder so people get my basic .project settings and can work in Eclipse nice and easily, but not my buildpath and .settings as they are system or even user specific. So to your .gitignore file add
    .settings/
    .buildpath
    and then right-click on the project in Eclipse and click Team --> Commit.

    Fill out your commit message, tick the items for .gitignore and .project (to add them to the index) and click 'Commit'
  12. Now your project is committed locally, you'll have a master branch in your local repository. Right click on your project in Eclipse, choose Team --> Push to upstream and you now have a fully functional remote repository with EGit support in Eclipse and a correct project structure.

I hope this helps someone else, but I know it will help me the next time I forget all this (and I will!)

Friday 11 May 2012

How to configure the writable directories in Symfony2' on Mac OS

I know it's my set-up, so please no comments (not like anyone except me reads this stuff anyway lol) but I can't be arsed to change it because it works for everything else I do. But every time I create a new Symfony2 project and run it for the first time I get errors like

[InvalidArgumentException]
The directory "/path/to/my/workspace/MyProject/app/cache/dev/annotations" is not writable.
PITA...

The answer's actually right there on the Symfony documentation, but if you can't be bothered to look for it (like me) or you somehow stumbled across this page first (doubt it) then the answer is as follows: Enter the follow commands but DON'T copy and paste... (see below)

rm -rf app/cache/*
rm -rf app/logs/*

sudo chmod +a "<name_of_your_http-server_user> allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs
sudo chmod +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs

Replace "<name of your http-server user>" with the actual name of the user that runs the httpd server on your system.

And if you get stuck...

Assuming you've got the error message above, or similar at least, enter:

ls -al /app/cache/
And you'll be able to work out from there what user you should be entering above. If you can't... you're reading the wrong blog.

Sunday 6 May 2012

Mapped properties in Symfony2 and Doctrine2 Entity inheritance

I discovered an interesting "feature" in the use of Doctrine's annotations today which caused me a little hunting around and trial and error to fix. But I'm posting about this here because a) as usual I'm useless at remembering stuff but more importantly b) I couldn't find any reference to this in the documentation and a lot of google searches didn't turn up anything relevant

The set-up

I have what I consider to be a fairly straight forward object graph:

  • Abstract BaseEntity
  • Extended by abstract BaseAuthUser
  • Extended by bundle specific User class

A (simplified) example of these classes are below:

/**
 * BaseEntity class
 * @ORM\MappedSuperclass
 */
abstract class BaseEntity {

    /**
     * @ORM\Column(type="bigint")
     * @ORM\Id
     * @ORM\GenerationStrategy(strategy="AUTO")
    private $id;

    // getters and setters ..l
}

/**
 * BaseAuthUser class
 * @ORM\MappedSuperclass
 */
abstract class BaseAuthUser extends BaseEntity {
    /**
  * @ORM\Column(type="string", length=100, unique=true)
  * @var string
  */
 private $email;
 /**
  * @ORM\Column(type="string", length=20, unique=true)
  * @var string
  */
 private $username;
 /**
  * @ORM\Column(type="string", length=20)
  * @var string
  */
 private $password;
 /**
  * @ORM\Column(type="string", length=32)
  * @var string
  */
 private $salt;

 /**
  * @ORM\Column(type="boolean", name="is_active")
  * @var boolean
  */
 private $isActive;
 
 // getters and setters ...
}

/**
 * MyBundleUser class
 * @ORM\Entity
 * @ORM\Table(name="auth_user")
 */
class MyBundleUser extends BaseAuthUser {

    // no specific properties mapped to database columns..
}

By annotating my classes this way, my understanding was that when I ran the command

php app/console doctrine:schema:create
I would have a single table called 'auth_user' built with the columns as defined in the BaseEntity and BaseAuthUser classes. And this was exactly what happened. Cool... one step closer

The next step was to ensure I have all the correct getters and setters and Doctrine has mapped my entity's metadata by running

php app/console doctrine:generate:entities MyBundleUser
which appeared to go well. As a result, I subsequently built the basic CRUD actions and templates by calling
php app/console doctrine:generate:crud

So at this point I have a working controller, and a form where I can add a new user. Or so I thought. When I actually filled out the form and hit submit, I got an error saying that my required email property was null. Um... well, that can't be right, I entered an email value. What's going on?

By running through debug, I could see that all the correct values were being received by the form, and my entity was being populated with the same values, but the SQL query was entering nulls. It turned out that the the

doctrine:generate:entities
command had added the private members and the associated getters and setters to my MyBundleUser class even though they were already defined in the BaseAuthUser class. So (my guess is) the form code was setting those values to my MyBundleUser class, but the Doctrine persistence code was looking at the getters and setters from the BaseEntity (somehow)...

Anyway - the solution was actually pretty simple but again, if the information is there in the documentation, I couldn't find it (if you know where it is, perhaps you'd like to leave a link in the comments...?). What's required, simply specify the name option in the @ORM\Column definitions and the property is no longer replicated in the sub-class. Once I had updated all of my classes to specify the name option, my object is persisted correctly.