[EXTENSION] phundament

Hi Schmunk! Got another question for you, about composer. I am using the latest phundament/app release (0.9.0). In ‘composer.json’ in the require-section, there is NO reference to the core Yii package. See:




"require": {

        "php": ">=5.3.2",

        "crisu83/yii-rights": "0.*",

        "mishamx/yii-user": "0.*",

        "phundament/p3admin": "0.8.*",

        "phundament/p3widgets": "0.8.*",

        "phundament/p3pages": "0.8.*",

        "phundament/p3media": "0.8.*",

        "phundament/themes/p3bootstrap": "0.7.*",

        "phundament/gii-template-collection": "0.7.*",

        "yiiext/fancybox-widget": "0.*",

        "yiiext/lipsum-widget": "0.*",

        "yiiext/migrate-command": "0.7.1.1"

    },



But when you run the installation script, Yii is installed after all! How is this possible?

Also: where is taken care of the directory structure? I also have installed the web-app branche. This installation doesnot create e.g. a directory called ‘www’. But I cannot find the source of where this is being configured.

I hope you can help me out here, as you’ve already done many times :)

Wait, I think I found the answer at http://getcomposer.org/doc/01-basic-usage.md

It is configured in the .lock file that yiisoft/yii is installed.

Hi ametad,

that’s one of the basic features of the dependency manager composer.

As an example I would like to refer to the two composer.json files of the packages p3admin and p3media.

When composer computes the dependencies it sees that yiisoft/yii is required by both packages mentioned above.

Therefore Yii gets installed before p3admin and p3media.

Moreover p3media requires a yii-application, that’s like a virtual package which is provided by p3admin by running a webapp command through ComposerCallback. Because p3media needs to setup permissions on data folders for uploaded files, it needs to be installed after a yiic webapp command has been executed.

In the yii-webapp branch I use the standard webapp command instead of my p3webapp command, but they just create different directory structures.

The .lock file just tracks the installed version of the packages. If you run php composer.phar install composer looks into the .lock file and installes the exact versions specified there. With this functionality you can ensure that you always get the same packages installed for your project, eg. in a development team or on your production server.

WIth php composer.phar update, you’ll get the latest versions which match with your composer.json file.

Best regards,

schmunk

Thanks!

And if you do an update with composer, are the files overwritten? In that case it is best practice to make adjustments always outside the vendor directory… I’ll keep that in mind.

But is a little bit tricky, because I had to make minor changes here and there. Per example the Rights- and User module don’t work perfectly together right after install.

For instance the WebUser.php class in the User module has a function called updateSession():




    public function updateSession() {

        $user = Yii::app()->getModule('user')->user($this->id);

        $this->name = $user->username;

        $userAttributes = CMap::mergeArray(array(

                                                'email'=>$user->email,

                                                'username'=>$user->username,

                                                'create_at'=>$user->create_at,

                                                'lastvisit_at'=>$user->lastvisit_at,

                                           ),$user->profile->getAttributes());

        foreach ($userAttributes as $attrName=>$attrValue) {

            $this->setState($attrName,$attrValue);

        }

    }




But in the config the assigned component for ‘user’ is RWebUser from the Rights module. This class does NOT have the updateSession() function. What I did is extend the RWebUser FROM WebUser, which in turn extends CWebUser. This way all custom-made functions are preserved from both modules.

Yes, the files are usually overwritten. But if you’ve run


php composer.phar update --prefer-source

you got "real" git repos for the packages, if available. If they have changes, composer will prompt you before overwriting the files.

You may also overwrite the packages from packages.phundament.com, see here. So you may include your own version, if eg. the maintainer does not accept a pull request.

You may also create a package like AWebUser, which combines the features you mentioned. Simply require this package then and adjust your config.

Ok, Nice to know that composer will prompt you before overwrite a file.

Perhaps I’ll make my own repo’s for Rights and User… because I have modified both to my needs. I want those repo’s not to be public because it contains some private data. Does Composer also work with repo’s from Bitbucket/Mercurial? They offer private repo’s for free B)

Another thing:

The forms in P3 (eg. ‘vendor\phundament\p3widgets\views\p3WidgetTranslation\_form.php’, etc) are made with standard Yii classes. Are you planning to use Bootstrap elements instead in future versions? It would look nice :) Perhaps I could send you a pull-request when I have customized my own form views.

Sure, Chris’ repos are from bitbucket.

Although I haven’t tested it yet, you should be able to include your private repos like this in your composer.json file:


   "repositories": [

    {

        "packagist": false

    },{

        "type":"vcs",

        "url": "https://bitbucket.com/ametad/yii-user"

    },{

        "type":"composer",

        "url": "http://packages.phundament.com"

    }

    ],

Make sure to include a composer.json in these repositories.

I had no time to update the views yet.

Have a look at gii-template-collection FullCrud "slim" template.

Hi Schmunk,

When updating with composer locally on a XAMPP config, I forget to turn on the MySQL database… Composer did download all the packages very nice with no errors - all like a charm :) But then the EMigrateCommand wants to do it’s job and finds no database so an error occurs: CDbConnection failed to open the DB connection.

How can I re-trigger Composer to finish the update process? When I run ‘composer.phar update’ again it says there are no new updates.

Greetings!

PS. happy 2013!

I tried some things after all, and saw in the config/console.php script what it does after an update:




'composer.callbacks' => array(

            // args for Yii command runner

            'post-update' => array('yiic', 'migrate'), // <-----------------

            'post-install' => array('yiic', 'migrate'),

            'phundament/p3admin-install' => array('yiic', 'p3webapp', 'create', realpath(dirname(__FILE__) . '/..'), 'git', '--interactive=0'),

            'phundament/themes/p3bootstrap-install' => array('yiic', 'p3bootstrap'),

            'phundament/p3media-install' => array('yiic', 'p3media'),

        ),



Did a command line instruction: ‘yiic migrate’ but it found no new migrations. I guess it is alright after all. Or am I missing something perhaps?

If you’ve configured (switched) a MySQL DB you can run

yiic migrate

again.

I’ll have a closer look next week, you always catch me, when I’m on vacation :)

Enjoy your free time man! :) I ‘see’ you later, bye bye.

Hopefully you’ve already solved your problem.

Just as an addition, there’s no magic in Phundament :)

When you run composer update or install the composer hook scripts simply trigger the yiic(ommands) from config/console.php.

So if you start with a SQLite installation and then switch to MySQL, either php composer.phar update or yiic migrate will do the job.

Greetings!

I’m having an issue accessing “Application”, in the administration menu. When i click it, i get this message:







<ul class="breadcrumbs breadcrumb"><li><a href="/Phundament3/www/index.php?r=p3admin&amp;lang=en">Backend</a><span class="divider">/</span></li><li class="active">p3admin</li></ul>

<h1>Application <small>Overview</small></h1>








<?

/**

 * Metadata Helps to get metadata about models,controllers and actions in application*

 *

 * For using you need:

 * 1. Place this file to directory with components of your application (your_app_dir/protected/components)

 * 2. Add it to 'components' in your application config (your_app_dir/protected/config/main.php)

 * 'components'=>array(

 *   'metadata'=>array('class'=>'Metadata'),

 *    ...

 *  ),

 * 3. Use:

 *   $user_actions = Yii::app()->metadata->getActions('UserController');

 *   var_dump($user_actions);

 *

 * @author Vitaliy Stepanenko <mail@vitaliy.in>

 * @version 0.2

 * @license BSD

 * @link http://www.yiiframework.com/extension/metadata/

 */


class Metadata extends CApplicationComponent

{


    /**

     * Get all information about application

     * if modules of your application have controllers with same name, it will raise fatall error

     *

     */

    public function getAll()

    {


        $meta = array(

            'models' => $this->getModels(),

            'controllers' => $this->getControllers(),

            'modules' => $this->getModules(),

        );

        foreach ($meta['controllers'] as &$controller) {

            $controller = array(

                'name' => $controller,

                'actions' => $this->getActions($controller)

            );

        }


        foreach ($meta['modules'] as &$module) {


            $controllers = $this->getControllers($module);


            foreach ($controllers as &$controller) {

                $controller = array(

                    'name' => $controller,

                    'actions' => $this->getActions($controller, $module)

                );

            }




            $module = array(

                'name' => $module,

                'controllers' => $controllers,

                'models' => $this->getModels($module),

            );


        }


        return $meta;


    }


    /**

     * Get actions of controller

     *

     * @param mixed $controller

     * @param mixed $module

     * @return mixed

     */

    public function getActions($controller, $module = null)

    {

        if ($module != null) {

            $path = join(DIRECTORY_SEPARATOR, array(Yii::app()->getModule($module)->basePath, 'controllers'));

            $this->setModuleIncludePaths($module);

        }

        else {

            $path = Yii::getPathOfAlias('application.controllers');

        }


        $actions = array();

        $file = fopen($path . DIRECTORY_SEPARATOR . $controller . '.php', 'r');

        $lineNumber = 0;

        while (feof($file) === false) {

            ++$lineNumber;

            $line = fgets($file);

            preg_match('/public[ \t]+function[ \t]+action([A-Z]{1}[a-zA-Z0-9]+)[ \t]*\(/', $line, $matches);

            if ($matches !== array()) {

                $name = $matches[1];

                $actions[] = $matches[1];

            }

        }


        return $actions;


    }


    /**

     * Set php include paths for module

     *

     * @param mixed $module

     */

    private function setModuleIncludePaths($module)

    {

        set_include_path(join(PATH_SEPARATOR, array(

                                                   get_include_path(),

                                                   //join(DIRECTORY_SEPARATOR,array(Yii::app()->modulePath,$module,'controllers')),

                                                   join(DIRECTORY_SEPARATOR, array(Yii::app()->modulePath, $module,

                                                                                   'components')),

                                                   join(DIRECTORY_SEPARATOR, array(Yii::app()->modulePath, $module,

                                                                                   'models')),

                                                   join(DIRECTORY_SEPARATOR, array(Yii::app()->modulePath, $module,

                                                                                   'vendors')),

                                              )));

    }


    /**

     * Get list of controllers with actions

     *

     * @param mixed $module

     * @return array

     */

    function getControllersActions($module = null)

    {

        $c = $this->getControllers($module);

        foreach ($c as &$controller) {

            $controller = array(

                'name' => $controller,

                'actions' => $this->getActions($controller, $module)

            );

        }

        return $c;

    }


    /**

     * Scans controller directory & return array of MVC controllers

     *

     * @param mixed $module

     * @param mixed $include_classes

     * @return array

     */

    public function getControllers($module = null)

    {


        if ($module != null) {

            $path = join(DIRECTORY_SEPARATOR, array(Yii::app()->getModule($module)->basePath, 'controllers'));

        }

        else {

            $path = Yii::getPathOfAlias('application.controllers');

        }

        $controllers = array_filter(scandir($path), array($this, 'isController'));

        foreach ($controllers as &$c) {

            $c = str_ireplace('.php', '', $c);

        }

        return $controllers;

    }


    /**

     * Scans models directory & return array of MVC models

     *

     * @param mixed $module

     * @param mixed $include_classes

     * @return array

     */

    public function getModels($module = null, $include_classes = false)

    {


        if ($module != null) {

            $path = join(DIRECTORY_SEPARATOR, array(Yii::app()->getModule($module)->basePath, 'models'));

        }

        else {

            $path = Yii::getPathOfAlias('application.models');

        }


        $models = array();

        if (is_dir($path)) {

            $files = scandir($path);

            foreach ($files as $f) {

                if (stripos($f, '.php') !== false) {

                    $models[] = str_ireplace('.php', '', $f);

                    if ($include_classes) {

                        include_once($path . DIRECTORY_SEPARATOR . $f);

                    }


                }

            }

        }

        return $models;


    }


    /**

     * Used in getModules() to filter array of files & directories

     *

     * @param mixed $a

     */

    private function isController($a)

    {

        return stripos($a, 'Controller.php') !== false;

    }




    /**

     * Returns array of module names

     *

     */

    public function getModules()

    {

        return array_keys(Yii::app()->modules);

    }


    /**

     * Used in getModules() to filter array of files & directories

     *

     * @param mixed $a

     */

    private function isModule($a)

    {

        return $a != '.' and $a != '..' and is_dir(Yii::app()->modulePath . DIRECTORY_SEPARATOR . $a);

    }


}

<?

/**

 * Metadata Helps to get metadata about models,controllers and actions in application*

 *

 * For using you need:

 * 1. Place this file to directory with components of your application (your_app_dir/protected/components)

 * 2. Add it to 'components' in your application config (your_app_dir/protected/config/main.php)

 * 'components'=>array(

 *   'metadata'=>array('class'=>'Metadata'),

 *    ...

 *  ),

 * 3. Use:

 *   $user_actions = Yii::app()->metadata->getActions('UserController');

 *   var_dump($user_actions);

 *

 * @author Vitaliy Stepanenko <mail@vitaliy.in>

 * @version 0.2

 * @license BSD

 * @link http://www.yiiframework.com/extension/metadata/

 */


class Metadata extends CApplicationComponent

{


    /**

     * Get all information about application

     * if modules of your application have controllers with same name, it will raise fatall error

     *

     */

    public function getAll()

    {


        $meta = array(

            'models' => $this->getModels(),

            'controllers' => $this->getControllers(),

            'modules' => $this->getModules(),

        );

        foreach ($meta['controllers'] as &$controller) {

            $controller = array(

                'name' => $controller,

                'actions' => $this->getActions($controller)

            );

        }


        foreach ($meta['modules'] as &$module) {


            $controllers = $this->getControllers($module);


            foreach ($controllers as &$controller) {

                $controller = array(

                    'name' => $controller,

                    'actions' => $this->getActions($controller, $module)

                );

            }




            $module = array(

                'name' => $module,

                'controllers' => $controllers,

                'models' => $this->getModels($module),

            );


        }


        return $meta;


    }


    /**

     * Get actions of controller

     *

     * @param mixed $controller

     * @param mixed $module

     * @return mixed

     */

    public function getActions($controller, $module = null)

    {

        if ($module != null) {

            $path = join(DIRECTORY_SEPARATOR, array(Yii::app()->getModule($module)->basePath, 'controllers'));

            $this->setModuleIncludePaths($module);

        }

        else {

            $path = Yii::getPathOfAlias('application.controllers');

        }


        $actions = array();

        $file = fopen($path . DIRECTORY_SEPARATOR . $controller . '.php', 'r');

        $lineNumber = 0;

        while (feof($file) === false) {

            ++$lineNumber;

            $line = fgets($file);

            preg_match('/public[ \t]+function[ \t]+action([A-Z]{1}[a-zA-Z0-9]+)[ \t]*\(/', $line, $matches);

            if ($matches !== array()) {

                $name = $matches[1];

                $actions[] = $matches[1];

            }

        }


        return $actions;


    }


    /**

     * Set php include paths for module

     *

     * @param mixed $module

     */

    private function setModuleIncludePaths($module)

    {

        set_include_path(join(PATH_SEPARATOR, array(

                                                   get_include_path(),

                                                   //join(DIRECTORY_SEPARATOR,array(Yii::app()->modulePath,$module,'controllers')),

                                                   join(DIRECTORY_SEPARATOR, array(Yii::app()->modulePath, $module,

                                                                                   'components')),

                                                   join(DIRECTORY_SEPARATOR, array(Yii::app()->modulePath, $module,

                                                                                   'models')),

                                                   join(DIRECTORY_SEPARATOR, array(Yii::app()->modulePath, $module,

                                                                                   'vendors')),

                                              )));

    }


    /**

     * Get list of controllers with actions

     *

     * @param mixed $module

     * @return array

     */

    function getControllersActions($module = null)

    {

        $c = $this->getControllers($module);

        foreach ($c as &$controller) {

            $controller = array(

                'name' => $controller,

                'actions' => $this->getActions($controller, $module)

            );

        }

        return $c;

    }


    /**

     * Scans controller directory & return array of MVC controllers

     *

     * @param mixed $module

     * @param mixed $include_classes

     * @return array

     */

    public function getControllers($module = null)

    {


        if ($module != null) {

            $path = join(DIRECTORY_SEPARATOR, array(Yii::app()->getModule($module)->basePath, 'controllers'));

        }

        else {

            $path = Yii::getPathOfAlias('application.controllers');

        }

        $controllers = array_filter(scandir($path), array($this, 'isController'));

        foreach ($controllers as &$c) {

            $c = str_ireplace('.php', '', $c);

        }

        return $controllers;

    }


    /**

     * Scans models directory & return array of MVC models

     *

     * @param mixed $module

     * @param mixed $include_classes

     * @return array

     */

    public function getModels($module = null, $include_classes = false)

    {


        if ($module != null) {

            $path = join(DIRECTORY_SEPARATOR, array(Yii::app()->getModule($module)->basePath, 'models'));

        }

        else {

            $path = Yii::getPathOfAlias('application.models');

        }


        $models = array();

        if (is_dir($path)) {

            $files = scandir($path);

            foreach ($files as $f) {

                if (stripos($f, '.php') !== false) {

                    $models[] = str_ireplace('.php', '', $f);

                    if ($include_classes) {

                        include_once($path . DIRECTORY_SEPARATOR . $f);

                    }


                }

            }

        }

        return $models;


    }


    /**

     * Used in getModules() to filter array of files & directories

     *

     * @param mixed $a

     */

    private function isController($a)

    {

        return stripos($a, 'Controller.php') !== false;

    }




    /**

     * Returns array of module names

     *

     */

    public function getModules()

    {

        return array_keys(Yii::app()->modules);

    }


    /**

     * Used in getModules() to filter array of files & directories

     *

     * @param mixed $a

     */

    private function isModule($a)

    {

        return $a != '.' and $a != '..' and is_dir(Yii::app()->modulePath . DIRECTORY_SEPARATOR . $a);

    }


}


Fatal error: Class 'Metadata' not found in /var/www/Phundament3/vendor/yiisoft/yii/framework/YiiBase.php on line 219


Call Stack:

    0.0001     647008   1. {main}() /var/www/Phundament3/www/index.php:0

    0.0228    4282984   2. CApplication->run() /var/www/Phundament3/www/index.php:13

    0.0229    4282984   3. CWebApplication->processRequest() /var/www/Phundament3/vendor/yiisoft/yii/framework/base/CApplication.php:162

    0.0229    4282984   4. CWebApplication->runController() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CWebApplication.php:142

    0.0272    5046632   5. CController->run() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CWebApplication.php:283

    0.0278    5117528   6. CController->runActionWithFilters() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CController.php:266

    0.0284    5245232   7. CFilterChain->run() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CController.php:292

    0.0285    5247464   8. CInlineFilter->filter() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/filters/CFilterChain.php:131

    0.0285    5247616   9. CController->filterAccessControl() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/filters/CInlineFilter.php:59

    0.0292    5382632  10. CFilter->filter() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CController.php:1146

    0.0321    5905024  11. CFilterChain->run() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/filters/CFilter.php:41

    0.0321    5905024  12. CController->runAction() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/filters/CFilterChain.php:134

    0.0322    5905024  13. CInlineAction->runWithParams() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CController.php:309

    0.0322    5906608  14. DefaultController->actionIndex() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/actions/CInlineAction.php:50

    0.0322    5906744  15. CController->render() /var/www/Phundament3/vendor/phundament/p3admin/controllers/DefaultController.php:62

    0.0322    5906984  16. CController->renderPartial() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CController.php:783

    0.0333    6022288  17. CBaseController->renderFile() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CController.php:870

    0.0334    6022448  18. CBaseController->renderInternal() /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CBaseController.php:96

    0.0335    6074440  19. require('/var/www/Phundament3/themes/frontend/views/p3admin/default/index.php') /var/www/Phundament3/vendor/yiisoft/yii/framework/web/CBaseController.php:127

    0.0339    6121560  20. include('/var/www/Phundament3/vendor/phundament/p3admin/views/default/index.php') /var/www/Phundament3/themes/frontend/views/p3admin/default/index.php:10

    0.0428    7280472  21. CModule->__get() /var/www/Phundament3/themes/frontend/views/p3admin/default/index.php:38

    0.0429    7280472  22. CModule->getComponent() /var/www/Phundament3/vendor/yiisoft/yii/framework/base/CModule.php:104

    0.0431    7282968  23. YiiBase::createComponent() /var/www/Phundament3/vendor/yiisoft/yii/framework/base/CModule.php:387



Hi echo66,

have a look at the upgrade document.

You have to add the metadata component to the p3admin module config in config/main.php


   'p3admin' => array(

        'components' => array(

            'metadata' => array(

                'class' => 'vendor.phundament.p3admin.components.Metadata',

            )

        )

    ),

I’ll try to remove that setting in the future, sorry about the inconvenience.

Best regards,

schmunk

just pushed 0.9.2 which should fix this issue, just run [font="Courier New"]php composer.phar update[/font]

Thanks for the quick response!

But i already had that and i get the same problem…




'p3admin' => array(

            'class' => 'vendor.phundament.p3admin.P3AdminModule',

            'params' => array('install' => false),

            'components' => array(

                'metadata' => array(

                    'class' => 'vendor.phundament.p3admin.components.Metadata',

                )

            )

        ),



You get the whole PHP class as output, followed by the stack trace?