[Solved] Alias “nordsoftware.yii_account” is invalid. Make sure it points to an existing directory or file.

When I integrate yii_account (https://github.com/nordsoftware/yii-account) to my application with Yii version 1.1.6, I encounter the folling error.

Alias “nordsoftware.yii_account” is invalid. Make sure it points to an existing directory or file.

I search the error in the google engine. Only two pages of result are matched.

==================== You can find the solution here, please read it carefully ==================

Sometimes it’s useful to namespace the whole module. For example, if you want to put testmodule under\mynamespace\modules\testmodule pointing to /var/www/common/mynamespace/modules/testmodule you should first create the following file structure:

/var/www/common/mynamespace/modules
  testmodule
    controllers
      DefaultController.php
    views
      default
        index.php
    TestmoduleModule.php

index.php view is the same as in regular module. TestmoduleModule.php and DefaultController.php are namespaced.

TestmoduleModule.php:

// define namespace:
namespace mynamespace\modules\testmodule;

// since class is now under namespace, global namespace
// should be referenced explicitly using "\":
class TestmoduleModule extends \CWebModule
{
    // setting non-global controllers namespace (also can be done via config)
    public $controllerNamespace = '\mynamespace\modules\testmodule\controllers';

    // usual module code
}

DefaultController.php:

<?php
// define namespace:
namespace mynamespace\modules\testmodule\controllers;

// since class is now under namespace, global namespace
// should be referenced explicitly using "\":
class DefaultController extends \Controller
{
    public function actionIndex()
    {
        $this->render('index');
    }
}

Now the only thing left is to add our module to the application. The best way to do it is to specify it in the application config file (protected/config/main.php):

// adding "mynamespace" namespace
Yii::setPathOfAlias('mynamespace', '/var/www/common/mynamespace/');

return array(
    'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
    'name'=>'My Web Application',

    'modules'=>array(
        'testmodule' => array(
            'class' => '\mynamespace\modules\testmodule\TestModuleModule',
        ),
    ),

Full Configuration

config/main.php

'aliases' => array(
    ......
    'nordsoftware' => __DIR__ . '/../modules/nordsoftware',
    ......
),

'modules' => array(
    ......
    'account' => array(
            'class' => '\nordsoftware\yii_account\Module',
        ),
    ......
),

'components' => array(
    ......
    'user' => array(
            'class' => '\nordsoftware\yii_account\components\WebUser',
    )
    ......
),
class Module extends \CWebModule
{
    public $controllerNamespace = '\nordsoftware\yii_account\controllers';
    ......

After reading this article, you can find the key point with red color labeled. If you want to search more about it, you can search with keyword “namespaced module in yii”

For details of namespace and alias, please check http://www.yiiframework.com/doc/guide/1.1/en/basics.namespace

A good way to validate composite unique key in Yii

You can find the way to validate composite unique key in Yii and know why you should do like this.

There are few reasons to use behavior and validation method instead of writing validation class

  1. we can’t attach a handler for CActiveRecord::onAfterFind() with only validator (this is needed for storing of old attributes of the model for proper validation when updating an existing record)
  2. CValidator doesn’t imply validation of several attributes

For download and some comments, please go to http://www.yiiframework.com/extension/composite-unique-key-validatable/

[Solved] PHP Auto Testing – NeatBeans+PHPUnit+Selenium

Please read this article carefully, because it can save you much time for building php auto-testing env.
Please do NOT try to fix one-by-one errors, except that you can get some fun as you need (Sometime some coders like to do it).

System configuration (even though it is not same as yours, please go ahead and I am sure it can help)
1. Windows
2. Xampp 1.8.2 (MYSQL 5.6, PHP 5.3)
3. Netbeans 7.4

There are some steps,
1. install phpunit with composer and Git
2. install Selenium
3. configure netbeans IDE

1. install phpunit with composer and Git

Note: Please do NOT waste time to use pear to install phpunit, because the phpunit offical has shut down the pear service from 12/31/2014

a) download Git from http://git-scm.com/download/win and install it, because composer needs

b) download composer from https://getcomposer.org/Composer-Setup.exe and install it

d)create file C:\Users\{windowusernamehere}\AppData\Roaming\Composer\composer.json with content

{
    "repositories": [
        {
            "type": "composer",
            "url": "http://packages.phundament.com"
        },
        {
            "type": "package",
            "package": {
                "name": "phpunit/php-invoker",
                "version": "1.1.3",
                "source": {
                    "type": "git",
                    "url": "http://github.com/sebastianbergmann/php-invoker",
                    "reference": "master"
                },
                "autoload": {
                    "classmap": [
                        "PHP/"
                    ]
                }
            }
        }
    ],
    "require": {
        "phpunit/phpunit": "4.1.*",
        "phpunit/phpunit-selenium": "*",
        "phpunit/phpunit-skeleton-generator": "*",
        "phpunit/dbunit": "*",
        "phpunit/phpunit-story": "*",
        "phpunit/php-invoker": "*",
        "phpunit/phpunit-mock-objects": "*"
    }
}

e) exceute command: composer global require “phpunit/phpunit=4.1.*” and then phpunit/phpunit-selenium/phpunit-skeleton-genertor/dbunit/phpunit-story/php-invoker/phpunit-mock-objects will be installed.

f) check batch files(phpunit.bat and phpunit-skelgen.bat) in C:\Users\{windowusernamehere}\AppData\Roaming\Composer\vendor\bin for netbeans configuration.

2. install Selenium

a) download selenium server from  http://selenium-release.storage.googleapis.com/2.42/selenium-server-standalone-2.42.2.jar

b) you can use the command to startup:  java -jar selenium-server-standalone-2.42.2.jar

The above two steps are from http://polyetilen.lt/en/installing-phpunit-with-composer-on-windows, so many thanks.

3. configure netbeans IDE

Please see to https://netbeans.org/kb/docs/php/phpunit.html

a) for installing netbeans selenium module for php, you can download from http://plugins.netbeans.org/plugin/37753/selenium-module-for-php

4. fix netbean bug for phpunit-skeleton-generator

You can fix the bug as https://netbeans.org/bugzilla/show_bug.cgi?id=245179

or use Netbeans 8.0 instead of Netbeans 7.4

follow the netbean instruction (https://netbeans.org/kb/docs/php/phpunit.html) to use it

Have fun!

Secondary installation

When I follow the above step to install for my new environment, I encounter a error like

“vendor/phpunit/php-invoker/PHP/ which does not appear to be a file nor a folder”

I do try to fix it and copy the vendor folder to new one. attached here

please extract to C:\Users\{windowusernamehere}\AppData\Roaming\Composer\

 

[Solved]PHPUnit Could not open input file – Two Solutions

Error Message: Could not open input file: .\pear\PHPUnit2\TextUI\TestRunner.php
Scence: run command: phpunit xxxTest
PHP Env: xampp 1.7.1 version

Solution One:
When you run the command phpunit xxxTest, there are some files you need to pay attention to:
1. xampp\php\phpunit.bat (code “”\xampp\php\.\php.exe” “.\pear\PHPUnit2\TextUI\TestRunner.php” %*”)

fix method: you can modify the code according to your installation path
“C:\xampp\php\php.exe” “C:\xampp\php\PEAR\PHPUnit2\TextUI\TestRunner.php” %*

Solution Two:
Related file: xampp\php\phpunit.bat and xampp\php\phpunit(this is a php file without php extension name)

xampp\php\phpunit code as
==================================================
require ‘PHPUnit2/TextUI/TestRunner.php’;
==================================================

xampp\php\phpunit.bat code as
==================================================
if “%PHPBIN%” == “” set PHPBIN=D:\xampp171\php\.\php.exe
if not exist “%PHPBIN%” if “%PHP_PEAR_PHP_BIN%” neq “” goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
“%PHPBIN%” “D:\xampp171\php\phpunit” %*
==================================================

I think you must fix your problem now.

NestedSetBehavior move root nodes – sorting[Solved]

NestedSetBehavior is a very good extension for manipulating tree with multiple roots. It only supports moveAsRoot and the new root is place as the last root, as

- 1. Mobile phones
    - 2. iPhone
    - 3. Samsung
        - 4. X100
        - 5. C200
        - 6. Motorola
- 7. Cars
    - 8. Audi
    - 9. Ford
    - 10. Mercedes

The node 9 can be moveAsRoot, but how to move Node 9 as root before 1. Mobile phones?

I have added some code based on the latest version https://gist.github.com/max107/10723289. This version
1. Disable single root mode
2. Root is not initiated same as PrimaryKey and set to Max(root)
3. The insertBefore, insertAfter, moveBefore, moveAfter does not support the case we mentioned before.

NestedSetBehavior Download here

insertBefore

public function insertBefore($target, $runValidation = true, $attributes = null) {
    if ($target->isRoot()) {
        return $this->addRootNode($target, $runValidation, $attributes, true);
    } else {
        return $this->addNode($target, $target->{$this->leftAttribute}, 0, $runValidation, $attributes);
    }
}

insertAfter

public function insertAfter($target, $runValidation = true, $attributes = null) {
    if ($target->isRoot()) {
        return $this->addRootNode($target, $runValidation, $attributes);
    } else {
        return $this->addNode($target, $target->{$this->rightAttribute} + 1, 0, $runValidation, $attributes);
    }
}

moveBefore

public function moveBefore($target) {
    if ($target->isRoot()) {
        return $this->moveAsRootSortable($target, true);
    } else {
        return $this->moveNode($target, $target->{$this->leftAttribute}, 0);
    }
}

moveAfter

public function moveAfter($target) {
    if ($target->isRoot()) {
        return $this->moveAsRootSortable($target);
    } else {
        return $this->moveNode($target, $target->{$this->rightAttribute} + 1, 0);
    }
}

Private method 1 (added)

private function moveAsRootSortable($target, $isBeforeMove=false) {
    $owner = $this->getOwner();
    if ($owner->getIsNewRecord())
        throw new CException(Yii::t('yiiext', 'The node should not be new record.'));

    if ($this->getIsDeletedRecord())
        throw new CDbException(Yii::t('yiiext', 'The node should not be deleted.'));

    if (!$target->isRoot())
        throw new CException(Yii::t('yiiext', 'the target node is not root'));

    $db = $owner->getDbConnection();

    if ($db->getCurrentTransaction() === null)
        $transaction = $db->beginTransaction();

    try {
        $source_tree_root = $owner->{$this->rootAttribute};
        $owner_db_temp_root = $owner->{$this->rootAttribute} * -1;
        $owner_left = $owner->{$this->leftAttribute};
        $owner_right = $owner->{$this->rightAttribute};
        $owner_level = $owner->{$this->levelAttribute};

        // update owner with temperary root, avoiding to be overwrited
        $owner->updateAll(
            array($this->rootAttribute => new CDbExpression($db->quoteColumnName($this->rootAttribute) . '* -1')),
                $db->quoteColumnName($this->leftAttribute) . '>=' . $owner->{$this->leftAttribute} . ' AND ' .
                $db->quoteColumnName($this->rightAttribute) . '<=' . $owner->{$this->rightAttribute} . ' AND ' .
                $db->quoteColumnName($this->rootAttribute) . '=' . CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount,
                array(CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount++ => $owner->{$this->rootAttribute}));

        // root sorting
        if ($owner->isRoot()) {
            // just shiftRoot for target node
            $owner_new_root = $this->shiftRoot($target->{$this->rootAttribute}, 1, $isBeforeMove);

            // update owner root
            $owner->updateAll(
                array($this->rootAttribute => $owner_new_root),
                $db->quoteColumnName($this->rootAttribute) . '=' . CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount,
                    array(CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount++ => $owner->{$this->rootAttribute} * -1));
        } else { // subtree to root
            // first step: source tree - shift left and right
            foreach (array($this->leftAttribute, $this->rightAttribute) as $attribute) {
                $condition = $db->quoteColumnName($attribute) . '>=' . $owner_left;
                $params = array();
                $condition .= ' AND ' . $db->quoteColumnName($this->rootAttribute) . '=' . CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount;
                $params[CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount++] = $source_tree_root;

                $owner->updateAll(array($attribute => new CDbExpression($db->quoteColumnName($attribute) . " - $owner_right + $owner_left - 1")), $condition, $params);
            }

            // second steps - just shiftRoot for target node, this can NOT be please before step 1, because this step will change root
            $owner_new_root = $this->shiftRoot($target->{$this->rootAttribute}, 1, $isBeforeMove);

            // new root
            $owner->updateAll(
                array(
                    $this->leftAttribute => new CDbExpression($db->quoteColumnName($this->leftAttribute) . " + 1 - ". $owner_level),
                    $this->rightAttribute => new CDbExpression($db->quoteColumnName($this->rightAttribute) . " + 1 - ". $owner_level),
                    $this->levelAttribute => new CDbExpression($db->quoteColumnName($this->levelAttribute) . " + 1 - ". $owner_level),
                    $this->rootAttribute => $owner_new_root,
                ), $db->quoteColumnName($this->leftAttribute) . '>=' . $owner_left . ' AND ' .
                $db->quoteColumnName($this->rightAttribute) . '<=' . $owner_right . ' AND ' .
                $db->quoteColumnName($this->rootAttribute) . '=' . CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount, array(CDbCriteria::PARAM_PREFIX . CDbCriteria::$paramCount++ => $owner_db_temp_root));
        }

        if (isset($transaction))
            $transaction->commit();
    } catch (Exception $e) {
        if (isset($transaction))
            $transaction->rollback();

        throw $e;
    }

    return true;
}

Private method 2 (added)

private function addRootNode($target, $runValidation, $attributes, $isBeforeInsert=false) {
    $owner = $this->getOwner();
    if (!(!$levelUp && $target->isRoot())) {
        throw new CException(Yii::t('yiiext', 'The target node should be root.'));
    }

    if ($runValidation && !$owner->validate())
        return false;
    $db = $owner->getDbConnection();

    if ($db->getCurrentTransaction() === null)
        $transaction = $db->beginTransaction();

    try {
        $owner->{$this->rootAttribute} = $this->shiftRoot($target->{$this->rootAttribute}, 1, $isBeforeInsert);
        $owner->{$this->leftAttribute} = 1;
        $owner->{$this->rightAttribute} = 2;
        $owner->{$this->levelAttribute} = 1;

        $this->_ignoreEvent = true;
        $result = $owner->insert($attributes);
        $this->_ignoreEvent = false;

        if (!$result) {
            if (isset($transaction))
                $transaction->rollback();

            return false;
        }

        if (isset($transaction))
            $transaction->commit();
    } catch (Exception $e) {
        if (isset($transaction))
            $transaction->rollback();

        throw $e;
    }

    return true;
}

Private Method 3 (Added)

private function shiftRoot ($key, $delta, $isBeforeInsert=false) {
    $owner = $this->getOwner();
    $db = $owner->getDbConnection();
    $op = $isBeforeInsert ? ">=": ">";
    $condition = $db->quoteColumnName($this->rootAttribute) . $op . $key;
    $params = array();
    
    $owner->updateAll(array($this->rootAttribute => new CDbExpression($db->quoteColumnName($this->rootAttribute) . sprintf('%+d', $delta))), $condition, $params);
    
    return $isBeforeInsert ? $key : ($key + 1);
}

php exec python script not working [Solved]

When you use exec in php to call shells like python, perl or other script. please follow the step below for your debugging:


exec("$your_command_here 2>&1", $output, $return_status);

the “2>&1” is the key point for debugging, because it can redirect the error message to standard output. Also, when you shell encounter an error, the $return_status will be 1 (success with 0).