Different versions of shell commands like PHP, Vi – find the true location of Mac/Unix commands, aliases and links

Sometimes it can be a challenge to uncover what terminal command is actually being run on Mac / Unix / Linux systems. Over time, old aliases, links and the repeated installation, upgrading and removal of software can lead to existing and even untouched default commands either unable to be found or running a different version than expected.

Recently we have been using Homebrew to swap in and out multiple versions of PHP (5.4, 5.6, 7.1 etc.) on Macs. Whilst great for quickly testing and developing across versions, this makes it possible to have strange occurrences, like the $ which [command] returning a different version of the software to the one which the shell actually executes!

The following location mismatch demonstrates the problem:

# Problem: Command or Software (in this case php)
# Reported as missing or runs at different location


$ php -v
-bash: /usr/local/bin/php: No such file or directory


$ which php
/usr/bin/php


# WTF ???

Different locations are being referenced by $ which [command]  and the shell.

To fix the discrepancy, use the $ hash [command] to refresh the shell’s command location cache:

# Result before hash command
$ command -v
php /usr/local/bin/php

$ hash php
$

# Result after command
$ command -v php
/usr/bin/php

# Same version recognized everywhere
$ which php
/usr/bin/php

$ php -v
PHP 5.5.36 (cli) (built: May 29 2016 01:07:06)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies

Great, order has returned to the universe and which is again pointing at the correct place. Keep in mind if you do replace (or re-link) the php at /usr/local/bin/php it will be executed instead of the /usr/bin/php, but now all commands should agree on the file’s location.

Debugging Aliases

The above situation can be particularly tricky when dealing with aliases.

If we define an alias and confirm it can be executed, the $ which [alias] and ls commands bizarrely return nothing! Where is the alias going? To find where and what the alias is actually running, utilise the $ type -a [command] command:

# Create alias and watch the confusing behavior
$ alias phpv='php -v'
phpv
PHP 5.5.36 (cli) (built: May 29 2016 01:07:06)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies


$ which phpv
$


$ ls -l phpv
ls: phpv: No such file or directory


# The type command reveals all (-a)
$ type -a phpv
phpv is aliased to `php -v'

Debugging Links

Links act slightly different again. As discovered in this blog post, vi links to vim on a mac, however the which, type -a and command -v commands only shows the link name, not the target:

# These commands give information on links (ls -l is most useful)

$ which vi
/usr/bin/vi

$ type -a vi
vi is /usr/bin/vi

$ command -v vi
/usr/bin/vi

$ ls -l /usr/bin/vi
lrwxr-xr-x 1 root wheel 3 21 Aug 15:29 /usr/bin/vi -> vim

Here we can see that although ls -l was useless for aliases and commands, it is good for showing where links point to.

Although only a summary, these quick commands give a few pointers for when a command either cannot be found or a different version than expected is executing. If you’re still struggling to locate an executed command or know of other handy tips, please leave a comment.

Please share if you find our free website useful, it really helps us produce more tutorials!

Advertisements

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.

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 🙂

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)!

Modify XML files using XSLT

XSLT can be great for transforming XML files, especially where information is stored in attributes thanks to the @ operator.

If you have a xml file like:

The elements can be combined into one with multiple attributes, ie:

<collection>
<field row0=”Value0″ row1=”Value1″ row2=”Value2″ row3=”Value3″ row4=”Value4″ row5=”Value5″ row6=”Value6″ row7=”Value7″ row8=”Value8″ row9=“Value9”></field>
</collection>

using the following XSLT:

A web search will reveal many handy online testing tools, such as:
http://xslt.online-toolz.com/tools/xslt-transformation.php

Additionally, many IDEs now come with tools and verifiers build in to facilitate XSLT translation of XML files. As much as we prefer using JSON where possible these days, XSLT can adds an extraordinary amount of functionality and flexibility to XML files.

Changing the default keyboard shortcut of a Chrome Extension

Changing the keyboard shortcuts of some Chrome web browser extensions can be a pain when the preferences option is non-editable in chrome://settings. A some-what longwinded workaround is to edit the source code of the extension directly. Often this is available on somewhere like GitHub.

To change a Chrome extension keyboard shortcut via its source code, the steps are as follows:

  1. Clone the extension source code to your computer
  2. Open the manifest.json file in the extension’s route directory. Edit or add this section:”omnibox”: { “keyword” : “key” }

Where “key” is the keyboard shortcut key itself. As an fyi, Chrome likes to calls its address bar the “omnibox”

  1. In chrome, go to: chrome://extensions/
  2. Delete the old extension (careful of deleting important data if relevant)
  3. Switch on developer mode in top right of page
  4. Select Load unpacked extension... and navigate to the cloned directory
  5. Verify the extension has loaded in Chrome and works correctly
  6. It is a security risk to browse the Internet with Chrome Extensions developer mode left on. Solve this by packing the extension into a single .crx file (a type of .zip file).
  7. Delete the newly created “unpacked” extension and click Pack extension... (you can sign the file with a .pem key but this is not necessary).
  8. Switch off developer mode in top right of page
  9. Nagivate to the directory above the cloned directory
  10. Drag the .crx file produced in the packing step onto the Chrome window
  11. The new extension should now appear on the chrome://extensions/ page
  12. Verify the correct result by navigating to chrome://settings/ -> Manage search engines...
  13. At bottom of page under “Search engines added by extensions” the keyboard shortcut should be updated and extension only appears once

 

You now have a modified keyboard shortcut for a Google Chrome extension. Some installations may experience problems with the browser disabling the extension unless it is officially released through the store (private repos are available). If the extension is disable then a restart of the web browser usually suffices in making the extension work again.

Easily Install Apache Tomcat on Mac OS X El Capitan

Please like or share this article if it helps you. Any problems, ask in comments!

By far the easiest way to install and configure an Apache Tomcat server on a mac is using the open-source homebrew package management suite. If you’re not already using homebrew, check out its popularity on GitHub. It makes open-source package management on mac 100 times cleaner than doing it manually (everything is stored in one place, packages are easy to remove, upgrade and find configs for).

There is a good tutorial here on installing homebrew if you do not already have it.

1)  –  Install Tomcat Server

Install tomcat with the brew install in terminal (as a normal user, not root):

$ brew install tomcat

This will take care of the downloading, installation and configuration of Tomcat and manage its dependencies as well. Take note of the output, brew commands are typically really good at displaying concise but useful info, error messages and help.

Homebrew keeps packages (known as kegs) in the Cellar, where you can check config and data files. It is a directory located at:

$ ls /usr/local/Cellar/

Verify the Tomcat installation using homebrew’s handy “services” utility:

$ brew services list

Tomcat should now be listed here. brew services are really useful for managing system services, type $ brew services --help for more info.

2)  –  Run Tomcat Server

We are going to start the server by executing Tomcat’s Catalina command with the “run” parameter as such:

$ ls /usr/local/Cellar/tomcat/

$ /usr/local/Cellar/tomcat/8.5.3/bin/catalina run

or more generally:

$ /usr/local/Cellar/tomcat/[version]/bin/catalina run

With [version] replaced with your installed version.

The version number and installation directory will have been listed by homebrew at the end of the installation output (typically the last line with a beer symbol in front). Catalina can also be set to start on system launch – although for security reasons we prefer to only run when needed (either using this command or more commonly via an IDE plugin).

Once the server is running you can navigate to the host page at:

http://localhost:8080/

 

3)  –  Configure Tomcat Server

To add and manage applications running on the server you will also need to edit a configuration file:

$ vim /usr/local/Cellar/tomcat/[version]/libexec/conf/tomcat-users.xml

With [version] again replaced with your installed version.

Towards the bottom of this short config file you will see a selection of users – all commented out by default. You need to uncomment one of these and give it the extra role “manager-gui” (preferably also changing the username and password for security). The resultant user entry should look something like this:

<user username="admin" password="password" roles="tomcat,manager-gui" />

After this you can navigate to the page (or click the “Manager App” link on the main Tomcat Server page):

http://localhost:8080/manager/html

Here you can view or delete the included sample application and deploy your own. Usually, it’s easiest to deploy applications in a dev / testing environment using an IDE like PHPStorm or NetBeans however, Tomcat’s web interface is useful also. For reference, deployed applications are usually then located under the directory:

/usr/local/Cellar/tomcat/[version]/libexec/webapps/

 

Please like or share this article if it helps you. Any problems, ask in comments!