Ярлыки

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

вторник, 28 февраля 2012 г.

Nano. Выделение текста.

Начало выделения: Alt-A или Ctrl-^
Навигация до момента выполнения действия над текстом
Удаление текста: Ctrl-K или F9
Копирование в буфер: Alt-6
Вставка текста из буфера: Ctrl-U или F10

суббота, 25 февраля 2012 г.

Zend Framework. Декоратор формы Description.

Например, данные пользователя не приняты на сервере, удобно послать сообщение методом setDescription.
Чтобы это работало надо установить декоратор для формы:
class LoginForm extends Zend_Form
{
    public function init() 
    {
        ...
        $this->setDecorators(array('Description', 'FormElements', 'Form'));
        ...
    }
}
После этого можно использовать:
$form = new LoginForm();
$form->setDescription('Неправильные имя или пароль');
$form->populate($formData)

пятница, 24 февраля 2012 г.

Git. Основы.

Работаем в одиночку


В каталоге проекта выполняем создаем репозиторий
git init
Добавляем файлы проекта
git add .
Делаем коммит (всегда предварительно надо добавлять отредактированные файлы)
git commit -m "First Commit"
Потребовался новый функционал - создаем ветку
git branch new-feature
Переключаемся на нее
git checkout new-feature
Вносим изменения и смотрим на них, индексируем, делаем коммит
git status
git add .
git commit -m "New feature added"
Делаем слияние веток, переключаемся на master
git checkout master
git merge new-feature
Если требуется внести небольшое изменение, можно не создавать ветку:
git stash
Вносим изменения и применяем их
git stash apply

Работа с удаленным репозиторием


Копируем репозиторий
git clone git://github.com/username/project.git master
Команда создала у вас репозитарий, и внесла туда копию ветки master проекта project.
Создаем новую ветку, вносим изменения в код
git branch new-feature
edit README
git add .git 
commit -m "Added a super feature"
Переходим в основную ветку, заберем последние изменения в проекте, и попробуем добавить новую фишку в проект:
git checkout master
git pull
git merge new-feature
Если есть конфликты - решаем, если нет, то сразу выгружаем
git push

Как сделать push в серверный репозиторий с файлами.

git config receive.denyCurrentBranch ignore
Также пишем в .git/hooks/post-receive
#!/bin/bash
cd ..
env -u GIT_DIR git reset --hard master
Помечаем как исполняемый
chmod a+x .git/hooks/post-receive

Копирование ветки удаленного репозитория

git checkout -b experimental origin/experimental

Создание пустой ветки без коммитов

git checkout --orphan mybranch

вторник, 21 февраля 2012 г.

Ubuntu. Установка пакета i386 на amd64.

Захотелось поставить антивирус avast! Linux Home Edition На сайте сборка для i386, иногда можно установить с помощью ключа --force-architecture
leon@Berta:~/Рабочий стол$ sudo dpkg -i --force-architecture avast4workstation_1.3.0-2_i386.deb
[sudo] password for leon: 
Выбор ранее не выбранного пакета avast4workstation:i386.
(Чтение базы данных ... на данный момент установлено 331920 файлов и каталогов.)
Распаковывается пакет avast4workstation:i386 (из файла avast4workstation_1.3.0-2_i386.deb)...
Настраивается пакет avast4workstation:i386 (1.3.0) ...
Обрабатываются триггеры для man-db ...
В данном случае работает

четверг, 16 февраля 2012 г.

Doctrine2. Введение.

Doctrine2 - object-relational mapper (ORM) для PHP 5.3.0+ Ядром является реализация шаблона Data Mapper

Что такое Entities?

 

Entities (классы модели) - объекты PHP, которым не надо расширять или реализовывать никакие абстрактные классы или интерфейсы. Есть некоторые ограничения, например,
- они не могут быть final или иметь методы final;
 - реализовывать clone или wakeup;
... Entity имеет свойства сохраняемые в базе данных и получаемые из нее.

 

 Пример модели: BUG TRACKER

 

Требования: Ошибка имеет описание, дату создания, статус, корреспондента и разработчика Ошибка может происходить с разными продуктами (платформами) Продукт имеет название Корреспондент и разработчик - оба пользователи системы Пользователь может сообщить об ошибке Назначенный разработчик должен исправить ошибку Пользователь может видеть все ошибки о которых он сообщил или для решения которых он назначен Ошибки могут быть представлены как список с постраничным выводом

 

Создание проекта

 

Установите Doctrine2
$ pear channel-discover pear.doctrine-project.org
$ pear install --alldeps doctrine/DoctrineORM
Создайте каталог проекта
$ mkdir project
$ cd project
Структура должна быть такой
project
|-- config
|   |-- xml
|   `-- yaml
`-- entities

 

 Начало проектирования модели

 

Создайте классы
// Bug.php
class Bug
{
    protected $id;
    protected $description;
    protected $created;
    protected $status;
}


// Product.php
class Product
{
    protected $id;
    protected $name;

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }
}


// User.php
class User
{
    protected $id;
    public $name; // public for educational purpose, see below

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }
}

Создание связей
// entities/Bug.php
use Doctrine\Common\Collections\ArrayCollection;

class Bug
{
    // ... (previous code)

    protected $products = null;

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

// entities/User.php
use Doctrine\Common\Collections\ArrayCollection;
class User
{
    // ... (previous code)

    protected $reportedBugs = null;
    protected $assignedBugs = null;

    public function __construct()
    {
        $this->reportedBugs = new ArrayCollection();
        $this->assignedBugs = new ArrayCollection();
    }
}
Для отладки классов не используйте var_dump() и тд, используйте Doctrine\Common\Util\Debug::dump() Создаем связи между пользователем и ошибкой
// entities/Bug.php
class Bug
{
    // ... (previous code)

    protected $engineer;
    protected $reporter;

    public function setEngineer($engineer)
    {
        $engineer->assignedToBug($this);
        $this->engineer = $engineer;
    }

    public function setReporter($reporter)
    {
        $reporter->addReportedBug($this);
        $this->reporter = $reporter;
    }

    public function getEngineer()
    {
        return $this->engineer;
    }

    public function getReporter()
    {
        return $this->reporter;
    }
}


// entities/User.php
class User
{
    // ... (previous code)

    protected $reportedBugs = null;
    protected $assignedBugs = null;

    // Используется именование методов в прошедшем времени,
    // это обозначает что назначение уже произошло и
    // и методы используются лишь для обеспечения согласованности ссылки. 
    // Очевидно что одностороннее использование методов 
    // User::addReportedBug() и User::assignedToBug()
    // в пользовательском коде не добавит ошибку в коллекцию
    // в свойствах Bug::$reporter или Bug::$engineer.
    // Использование этих методов и вызов Doctrine не обновят
    // представление коллекций в базе данных.

    public function addReportedBug($bug)
    {
        $this->reportedBugs[] = $bug;
    }

    public function assignedToBug($bug)
    {
        $this->assignedBugs[] = $bug;
    }
}

 

Метаданные отображения для классов модели

 

Далее надо добавить метаданные для Doctrine, чтобы классы модели могли быть сохранены в базе данных. Это можно сделать 3 способами: XML, YAML, аннотации. В первом и втором случае, мы создаем файлы и кладем их в каталоги project/config/xml и project/config/yaml соотвественно. В последнем - аннотации добавляются непосредственно в код класса. Пример для продукта
// entities/Product.php
/**
 * @Entity @Table(name="products")
 **/
class Product
{
    /** @Id @Column(type="integer") @GeneratedValue **/
    protected $id;
    /** @Column(type="string") **/
    protected $name;

    // .. (other code)
}

<!-- config/xml/Product.dcm.xml -->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                    http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

      <entity name="Product" table="products">
          <id name="id" type="integer">
              <generator strategy="AUTO" />
          </id>

          <field name="name" type="string" />
      </entity>
</doctrine-mapping>


# config/yaml/Product.dcm.yml
Product:
  type: entity
  table: products
  id:
    id:
      type: integer
      generator:
        strategy: AUTO
  fields:
    name:
      type: string


Для поля id дерективы указывают на то, что будет использован механизм генерации родной для СУБД (AUTO INCREMENT для MySQL, например). Для Bug
// entities/Bug.php
/**
 * @Entity @Table(name="bugs")
 **/
class Bug
{
    /**
     * @Id @Column(type="integer") @GeneratedValue
     **/
    protected $id;
    /**
     * @Column(type="string")
     **/
    protected $description;
    /**
     * @Column(type="datetime")
     **/
    protected $created;
    /**
     * @Column(type="string")
     **/
    protected $status;

    /**
     * @ManyToOne(targetEntity="User", inversedBy="assignedBugs")
     **/
    protected $engineer;

    /**
     * @ManyToOne(targetEntity="User", inversedBy="reportedBugs")
     **/
    protected $reporter;

    /**
     * @ManyToMany(targetEntity="Product")
     **/
    protected $products;

    // ... (other code)
}


<!-- config/xml/Bug.dcm.xml -->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                    http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

    <entity name="Bug" table="bugs">
        <id name="id" type="integer">
            <generator strategy="AUTO" />
        </id>

        <field name="description" type="text" />
        <field name="created" type="datetime" />
        <field name="status" type="string" />

        <many-to-one target-entity="User" field="reporter" inversed-by="reportedBugs" />
        <many-to-one target-entity="User" field="engineer" inversed-by="assignedBugs" />

        <many-to-many target-entity="Product" field="products" />
    </entity>
</doctrine-mapping>

# config/yaml/Bug.dcm.yml
Bug:
  type: entity
  table: bugs
  id:
    id:
      type: integer
      generator:
        strategy: AUTO
  fields:
    description:
      type: text
    created:
      type: datetime
    status:
      type: string
  manyToOne:
    reporter:
      targetEntity: User
      inversedBy: reportedBugs
    engineer:
      targetEntity: User
      inversedBy: assignedBugs
  manyToMany:
    products:
      targetEntity: Product

Тут определны две ссылки на сущность User. Имя класса связанной сущности задается тэгом targetEntity. Имеет место двунаправленная связь, поэтому с помощью тэга inversedBy указываем атрибут связанной сущности, соответствующей нашему объекту. И наконец для User
// entities/User.php
/**
 * @Entity @Table(name="users")
 **/
class User
{
    /**
     * @Id @GeneratedValue @Column(type="integer")
     * @var int
     **/
    protected $id;

    /**
     * @Column(type="string")
     * @var string
     **/
    protected $name;

    /**
     * @OneToMany(targetEntity="Bug", mappedBy="reporter")
     * @var Bug[]
     **/
    protected $reportedBugs = null;

    /**
     * @OneToMany(targetEntity="Bug", mappedBy="engineer")
     * @var Bug[]
     **/
    protected $assignedBugs = null;

    // .. (other code)
}


<!-- config/xml/User.dcm.xml -->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                    http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

     <entity name="User" table="users">
         <id name="id" type="integer">
             <generator strategy="AUTO" />
         </id>

         <field name="name" type="string" />

         <one-to-many target-entity="Bug" 
                         field="reportedBugs"
                         mapped-by="reporter" />
         <one-to-many target-entity="Bug" 
                         field="assignedBugs" 
                         mapped-by="engineer" />
     </entity>
</doctrine-mapping>

# config/xml/User.dcm.yml
User:
  type: entity
  table: users
  id:
    id:
      type: integer
      generator:
        strategy: AUTO
  fields:
    name:
      type: string
  oneToMany:
    reportedBugs:
      targetEntity: Bug
      mappedBy: reporter
    assignedBugs:
      targetEntity: Bug
      mappedBy: engineer
Связи один-ко-многим уже определены на стороне владельца (Bug), поэтому поэтому просто указываем его атрибут с помощью тэга mappedBy.

 

Настройка EntityManager

 

Выборку и сохранение сущностей в базе данных обеспечивает EntityManager. Для этого его необходимо создать и настроить.
// bootstrap_doctrine.php

// See :doc:`Configuration <../reference/configuration>` for up to date autoloading details.
use Doctrine\ORM\Tools\Setup;

require_once "Doctrine/ORM/Tools/Setup.php";
Setup::registerAutoloadPEAR();

// Create a simple "default" Doctrine ORM configuration for XML Mapping
$isDevMode = true;
$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
// or if you prefer yaml or annotations
//$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/entities"), $isDevMode);
//$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);

// database configuration parameters
$conn = array(
    'driver' => 'pdo_sqlite',
    'path' => __DIR__ . '/db.sqlite',
);

// obtaining the entity manager
$entityManager = \Doctrine\ORM\EntityManager::create($conn, $config);
Продолжение следует (или нет) ...

среда, 8 февраля 2012 г.

Debian. Обновление php на debian 5 lenny.

На данный момент доступна версия 5.3.10

Добавляем реп в /etc/apt/sources.list
deb http://php53.dotdeb.org oldstable all
deb-src http://php53.dotdeb.org oldstable all

Качаем и ставим ключ
wget http://www.dotdeb.org/dotdeb.gpg
cat dotdeb.gpg | sudo apt-key add -

Обновляем
apt-get update
apt-get dist-upgrade

вторник, 7 февраля 2012 г.

Zend Framework. Создание rss или atom потока.

Форматируем данные
//Create an array for our feed
$feed = array();
 
//Setup some info about our feed
$feed['title']          = "ZendCoding.com's Newest Stories";
 
$feed['link']           = 'http://www.zendcoding.com/newest-stories.rss';
 
$feed['charset']    = 'utf-8';
 
$feed['language']   = 'en-us';
 
$feed['published']  = time();
 
$feed['entries']    = array();//Holds the actual items
 
//Loop through the stories, adding them to the entries array
foreach($stories->fetchAll($select) as $story){
    $entry = array(); //Container for the entry before we add it on
 
    $entry['title']     = $story->title; //The title that will be displayed for the entry
 
    $entry['link']      = $story->url; //The url of the entry
 
    $entry['description']   = $story->teaser; //Short description of the entry
 
    $entry['content']   = $story->description; //Long description of the entry
 
    //Some optional entries, usually the more info you can provide, the better
    $entry['lastUpdate']    = $story->modified; //Unix timestamp of the last modified date
 
    $entry['comments']  = $story->commentsUrl; //Url to the comments page of the entry
 
    $entry['commentsRss']   = $story->commentsRssUrl; //Url of the comments pages rss feed
 
    $feed['entries'][]  = $entry;
}

Импорт в поток
$feedObj = Zend_Feed::importArray($feed, 'rss'); //Or importArray($feed, 'atom');

Вывод
//Return the feed as a string, we're not ready to output yet
$feedString = $feedObj->saveXML();
 
//Or we can output the whole thing, headers and all, with
$feedObj->send();

четверг, 2 февраля 2012 г.

Git. Установка и настройка репозитория для веб-сайта.

Установка git на debian, ubuntu:
$ sudo apt-get install git-core

Если хотим, чтобы каталоги или файлы были исключены из репозитория, надо создать файл .gitignore в каталоге сайта:
$ touch .gitignore
$ cat .gitignore >> images/
$ cat .gitignore >> robots.txt

Создаем репозиторий на локальной машине. Для этого заходим в каталог сайта:
$ git init
Initialized empty Git repository in /var/www/mysite
$ git commit -a -m "my first commit"

Доступ будет по ssh. На сервере в корне сайта создаем каталог и пустой репозиторий:
$ mkdir mysite.git && cd mysite.git
$ git init --bare
Initialized empty Git repository in /var/www/mysite/mysite.git/

Далее на сервере указываем действие, которое будет совершаться после коммита. Для этого в скрипт post-recieve добавляем переменную, которая указывает на каталог, в который будут распаковываться файлы. Ставим права на исполнение:
$ cat > hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/var/www/mysite git checkout -f
$ chmod +x hooks/post-receive

На локальной машине выгружаем репозиторий на сервер:
$ git remote add origin user@mysite:/var/www/mysite/mysite.git
$ git push origin master
user@mysite's password: 
Counting objects: 6735, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6512/6512), done.
Writing objects: 100% (6735/6735), 22.22 MiB | 191 KiB/s, done.
Total 6735 (delta 2614), reused 0 (delta 0)
To user@mysite:/var/www/mysite
 * [new branch]      master -> master