Ярлыки

.htaccess (4) тестирование (8) шаблоны проектирования (3) css (5) Debian (6) docker (2) Doctrine2 (6) Git (6) html (4) java (6) javascript (13) jquery (11) LFS (3) linux (23) mac os (4) mod_rewrite (2) MSSQL (4) MySQL (18) ORM Doctrine (17) patterns (3) PDO (3) perl (7) PHP (64) PHPUnit (8) Python (15) SEO (2) Silex (1) SimpleXML (1) SQL (14) ssh (4) Ubuntu (24) Yii1 (1) Zend Framework (19) ZendFramework2 (8)

понедельник, 19 августа 2013 г.

ZendFramework2. Собственный модуль авторизации и ACL, объединяющий ZfcUser, BjuAuthorize, Doctrine2.

Я опущу установку приложения Zend Framework 2 и установку модулей ZfcUser, BjuAuthorize, Doctrine2. Перейдем сразу к созданию собственного модуля.

Создаем структуру модуля

/module/MyUser
    /config
        doctrineconnection.local.php.dist
        module.config.php
    /src
        /MyUser
            /Entity
                Role.php
                User.php
    Module.php
Добавляем модуль в /config/application.config.php.

doctrineconnection.local.php.dist настройки подключения Doctrine, нужен только если они не указаны где-то за пределами модуля. Как правило настройки уже присутствуют в каталоге /config/autoload приложения.

return array(
    'doctrine' => array(
        'connection' => array(
            'orm_default' => array(
                'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
                'params'      => array(
                    'host'     => '127.0.0.1',
                    'port'     => '3306',
                    'user'     => 'dbuser',
                    'password' => '',
                    'dbname'   => 'mydb'
                )
            )
        )
    )
);
MyUser/Module.php
class Module {
    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }

    public function getAutoloaderConfig()
    {
        return array(
            'Zend\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }
}
MyUser/config/module.config.php
return array(
    'doctrine' => array(
        'driver' => array(
            // перектрываем настройки zfc-user-doctrine-orm
            // используем AnnotationDriver
            // и указываем путь к каталогу с классами модели
            'zfcuser_entity' => array(
                'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
                'paths' => __DIR__ . '/../src/MyUser/Entity',
            ),

            'orm_default' => array(
                'drivers' => array(
                    'MyUser\Entity' => 'zfcuser_entity',
                ),
            ),
        ),
    ),

    'zfcuser' => array(
        // указываем, что ZfcUser должен использовать наш класс пользователя
        'user_entity_class'       => 'MyUser\Entity\User',
        // указываем ZfcUserDoctrineORM игнорировать сущности по-умолчанию
        'enable_default_entities' => false,
    ),

    'bjyauthorize' => array(
        // Using the authentication identity provider, 
        // which basically reads the roles from the auth service's identity
        'identity_provider' => 
            'BjyAuthorize\Provider\Identity\AuthenticationIdentityProvider',

        'role_providers' => array(
            // используем репозиторий объектов
            // для загрузки ролей в ACL
            'BjyAuthorize\Provider\Role\ObjectRepositoryProvider' => array(
                'object_manager'    => 'doctrine.entity_manager.orm_default',
                // указываем наш класс для ролей
                'role_entity_class' => 'MyUser\Entity\Role', 
            ),
        ),
    ),
);

Создаем классы User и Role

Проще всего скопировать шаблоны классов из модуля bjy-authorize
 /vendor/bjyoungblood/bjy-authorize/data/Role.php.dist
 в
 /module/MyUser/src/MyUser/Entity/Role.php
и
 /vendor/bjyoungblood/bjy-authorize/data/User.php.dist
в /module/MyUser/src/MyUser/Entity/User.php
в этим классах везде меняем пространство имен на наше
Mynamespace на MyUser\Entity

Проверяем

> vendor/bin/doctrine-module orm:validate-schema
[Mapping]  OK - ...
[Database] FAIL - .....
Схема модели работает, осталось обновить базу данных (точнее создать таблицы)
> vendor/bin/doctrine-module orm:schema-tool:update --force
Updateing database schema...
Database schema updated successfully! "6" queries were executed
Теперь в базе данных имеем три таблицы
    role
    users
    users_roles
Добавляем роли в таблицу
INSERT INTO `role` 
    (`id`, `parent_id`, `roleId`) 
VALUES
    (1, NULL, 'guest'),
    (2, 1, 'user'),
    (3, 2, 'moderator'), 
    (4, 3, 'administrator');

ZendFramework2. Использование собственных модулей на примере расширения возможностей ZfcUser.

Изменение маршрутов

По умолчанию модуль использует маршрут user. Мы хотим поменять на account.
Важно!!! Наш модуль регистрируется после стандартного модуля.
В таком случае настройки подхватываются последовательно и мы можем перекрыть стандартные настройки модуля ZfcUser в файле настроек нашего модуля.
return array(

    ...

    // Перекрываем маршрут zfcuser
    'router' => array(
        'routes' => array(
            'zfcuser' => array(
                'options' => array(
                    'route' => '/account',
                ),
            ),
        ),
    ),
);

Изменение скриптов вида

Каталог скриптов вида стандартного модуля называется 'zfc-user'.
Например, шаблон с формой регистрации будет 'view/zfc-user/user/register.phtml'.
Все что нам нужно, это просто создать альтернативный шаблон в нашем модуле с аналогичным путем и убедится, что шаблоны нашего модуля подхватываются уровнем вида приложения.
Для этого в настройках модуля должно быть следующее:
return array(
    ...

    // Указываем менеджеру вида путь к шаблонам в нашем модуле
    'view_manager' => array(
        'template_path_stack' => array(
            'application' => __DIR__ . '/../view',
        ),
    ),
);

Изменение формы

ZfcUser генерирует событие после выполнения метода init, то есть после создания формы со всеми элементами. Событие так и называется 'init' а идентификатор 'ZfcUser\Form\Register'.Таким образом, если мы хотим, например, добавить чекбокс в форму, то у нас есть такая возможность. Мы должны использовать слушатель события 'init'. Нам нужно создать слушатель в классе нашего модуля. Класс модуля должен реализовавать интерфейс 'Zend\ModuleManager\Feature\BootstrapListenerInterface'
в котором есть метод onBootstrap.
...
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
...

class Module implements BootstrapListenerInterface {

...

    public function onBootstrap(Event $e){
        $app = $e->getParam('application');
        // $em объект Zend\EventManager\SharedEventManager
        $em  = $app->getEventManager()->getSharedManager();

        $em->attach('ZfcUser\Form\Register', 'init', function($e) {
            // $form объект ZfcUser\Form\Register
            $form = $e->getTarget();

            $form->add(array(
                'name' => 'accept',
                'options' => array(
                     'label' => 'Accept Terms of Use',
                ),
                'attributes' => array(
                    'type' => 'checkbox'
                ),
            ));
        });
    }

...

}
Похожий вариант с ZfcUser\Form\RegisterFilter, котoрый тоже генерирует событие init:
public function onBootstrap(Event $e){
    $app = $e->getParam('application');
    // $em объект Zend\EventManager\SharedEventManager
    $em  = $app->getEventManager()->getSharedManager();

    $em->attach('ZfcUser\Form\Register', 'init', function($e) {
        // $form объект ZfcUser\Form\Register
        $form = $e->getTarget();

        $form->add(array(
            'name' => 'accept',
            'options' => array(
                'label' => 'Accept Terms of Use',
            ),
            'attributes' => array(
                'type' => 'checkbox'
            ),
        ));
    });
}
К сожалению, далеко не все модули используют EventManager для оповещения о событиях ;-(
В таком случае этот подход не будет работать.

суббота, 17 августа 2013 г.

Javascript. Один из вариантов наследования объектов.

function foo()
{
    this.name = "foo";
    this.testFoo = function () 
    {
        return "testFoo()";
    }
}

function bar()
{
    foo.call(this); // меняем контекст foo на bar
    this.getName = function () 
    {
        return this.name + "bar";
    }
    this.testBar = function ()
    {
        return "testBar()";
    }
    this.testFoo = this.testBar;
}

mybar = new bar();
alert(mybar.getName()); // foobar
alert(mybar.testFoo()); // testBar()

пятница, 16 августа 2013 г.

Git. Поврежденный репозиторий, fatal: loose object.

Виртуальная машина жестко повесила ubuntu. Помог только сброс питания. ;-( Как результат - повреждение репозитория Git. ;-((( В консоли выглядит следующим образом
user@user-laptop:~/www/project$ git status
error: object file .git/objects/41/42ee9d7ea7c1bceac107c406e865fac72411fd is empty
fatal: loose object 4142ee9d7ea7c1bceac107c406e865fac72411fd 
(stored in .git/objects/41/42ee9d7ea7c1bceac107c406e865fac72411fd) is corrupt
Хорошо, мастер-репозиторий есть на тестовом сервере и на продакшене. Архивируем локальный проект и клонируем мастер на локальную машину. Накатываем все, что указано в .gitignore на новое дерево проекта; ставим права на каталоги, если надо.