When mocking a method in PHPUnit produces a “cannot be configured” error

When mocking an object in PHPUnit testing, if you receive the following error even when the function name  is correct. For example, if mocking non-custom Doctrine Repositories (i.e. no SomeEntityRepository class) will cause:

Error:
Trying to configure method “getUser” which cannot be configured because it does not exist, has not been specified, is final, or is static

This occurs on a PHPUnit_Framework_MockObject_MockObject object when using the PHPUnit_Framework_TestCase and PHPUnit_Framework_MockObject_MockBuilder.

In the case of mocking Doctrine find calls, often this error means $methodName parameter in the getMockBuilder($methodName) function is incorrect. For example the following code is incorrect:

// Produces error
$itemRepoMock = $this
  ->getMockBuilder('AppBundle\Entities\ItemRepository')
  ->method('find')
  ->disableOriginalConstructor()
  ->getMock();
$itemRepoMock
  ->expects($this->any())
  ->method('find')
  ->will($this->returnValue($itemMock));

Here you need to specify Doctrine’s base EntityRepository class instead, so:
AppBundle\Entities\ItemRepository
becomes
Doctrine\ORM\EntityRepository
The same example:

// Fixed
$itemRepoMock = $this
  ->getMockBuilder('Doctrine\ORM\EntityRepository')
  ->method('find')
  ->disableOriginalConstructor()
  ->getMock();
$itemRepoMock
  ->expects($this->any())
  ->method('find')
  ->will($this->returnValue($itemMock));

As a defined ItemRepository does not exist, neither dies its find function, even though you can usually use the inferred name.

Advertisements

Fix a Git Commit Message Typo

If after quickly typing in a commit you notice a typo, as such:

git commit -m "this is splet wrong"

You can quickly fix this using Git’s --amend flag, as such:

  1. Type: git commit --amend
  2. By default, the vi editor is opened. press a to enter INSERT mode and make changes
  3. Press ESC to leave INSERT mode and save by typing :wq (write and quit), if you accidently made everything 10x worse, you can cancel by typing :q! (quit, ignoring changes)
  4. Your commit now has an updated commit message and you can push as normal

No more embarrassing errors highlighting non-compliance with the absurd and illogical English (or other) written language.

Doctrine findBy and findOneBy Argument 2 passed must be an instance of […], none given

Argument 2 passed to AppBundle\Entities\WrappingPaperRepository::findWrapperInfoForProduct() must be an instance ofAppBundle\Entities\Product, none given, called in .. .php

This error sometimes occurs when converting a “findBy” call located outside the Repository into a named repository function. Whilst you can of course make repo custom function arguments also use arrays of parameters, often when writing a quick database lookup this is too much hassle and we just specify them like so:

  //Repository File
  function findInfoForProduct(Product $product) {
    // ..custom logic
  }

But this is different to how Doctrine’s findBy and findOneBy functions work – above we provide a single parameter of type product – they take an array of parameters as such:

  //Repository File
  $em->getRepository('AppBundle\Entities\Product')->findBy(['product' => $product]);

Remove the “array(” or “[” characters from your repository function call and your data retrieval service will work fine, or at least get you a bit further towards the next issue!

Doctrine convention adherence leads to much simpler entity classes, no picky join column specification. A standard bi-directional one-to-many join becomes simply:

<?php
use Doctrine\Common\Collections\ArrayCollection;

/** @Entity **/
class Product
{
    /**
     * @OneToMany(targetEntity="Feature", mappedBy="product")
     **/
    private $features;

    public function __construct() {
        $this->features = new ArrayCollection();
    }
}

/** @Entity **/
class Feature
{
    /**
     * @ManyToOne(targetEntity="Product", inversedBy="features")
     **/
    private $product;
}

Nice and straight forward.

Of course, if you do want to specify the join column manually, it would be:

/** @Entity **/
class Feature
{
    /**
     * @ManyToOne(targetEntity="Product", inversedBy="features")
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id")
     **/
    private $product;
}

The getters & setters can be auto-generated with the following calls from the server’s command line:

app/console doctrine:generate:entities AppBundle:Product
app/console doctrine:generate:entities AppBundle:Feature

Alternatively, modern IDE tools like PHPStorm can also generate the standard for you. Chaining is a great feature to encourage on setter methods, simply return $this after setting an entity property.

Using Twig’s default() filter to avoid “Variable some_var does not exist”

References to undefined variables are a common cause of web pages not displaying when using Twig. A simple mention of an undefined variable can cause 500 errors:

{{ some_var }}

Variable some_var does not exist in..

Whilst turning strict_variables off in the twig config will obviously hide the error and is best for production, during development hiding errors can ultimately making spotting bugs harder. A better solution is using Twig’s default() filter like so:

{{ some_var|default("") }}

This will print the variable if it exists or nothing if it is not defined.
For if statements and loops, there are 3 choices:

  1. The default() filter:
  2. {% if some_var|default(false) %}some text{% endif %}
  3. The fine grain but hideously verbose control of defined:
  4. {% if some_var is defined and some_var %}some text{% endif %}
  5. The empty filter:
  6. {% if some_var is not empty %}some text{% endif %}

There are also lots of other useful tests, filters and functions that Twig provides out of the box, check out their documentation pages for more info. Hope this helps. Please like and share if it does 🙂

AngularJS IE11- (ONLY) SyntaxError on ng-view div when opening WebSockets socketHelper

A strange error cropped up today. The Angular 1 JS WebSocket() based application worked fine on all browser exception Internet Explorer 11. The error reported was as such:

SyntaxError <div class="ng-scope" ng-view="">
{
 ABORT_ERR: 20,
 code: <Permission denied>,
 constructor: { },
 ...

Far from actually being a syntax error, the actual cause turned out to be a missing / (forward slash) in the WebSocket connection creation call to:

conn = new WebSocket('ws:/localhost:3001');

This of course should have been:

conn = new WebSocket('ws://localhost:3001');

Only Internet Explorer 8 – 11 experienced this error. Whilst there is a definite syntax error in specifying a websocket url, it’s hard to tell if the error is perhaps bubbling up or causing an unrelated issue further along the command sequence.

Which Symfony Version number?

The Symfony console provides a -V option. This can be handy for quickly finding out which version of Symfony a system is running but it has moved location a bit over the years (note the uppercase -V or use –version):

$ php bin/console -V
Symfony version 3.1.2 - app/dev/debug

If this produces a bunch of errors about autoload.php then you need to run composer install to install other required parts of Symfony. Whilst if you receive a command not found error then try:

$ php app/console -V
Symfony version 2.7.10 - app/dev/debug

If still a command not found error then try:

$ php lib/vendor/symfony/data/bin/symfony -V
Symfony version 1.4.20

In all versions, running console without -V will produce a long list of all the commands available, along with the version info. This is very useful and really good regular learning exercise, the options really show how Symfony works.

As we can see, the console command moved to the project folder’s bin/ folder as of version 3.0 in Symfony2 versions the console command lived in the project’s app/ directory, whilst if only lib/vendor/symfony/data/bin/symfony exists then you’re using Symfony version 1 (now an obsolete legacy platform)!