проголосовало
4 пользователей

Вопросы по PHP программированию

PHP программирование →  Оптимизируем расположение контента

Всем известно, что много статического контента, например, картинок, каких-либо файлов, держать в одной папке не кошерно:)
Было бы неплохо разбрасывать контент автоматически по папочкам, например, в зависимости от айдишника единицы контента.

Следующие функции решают эту это проблему:


/**
* Get path for image by ID
* Returns path like /1/2/12 when id = 12
*
* @param int $id
*/

if ( ! function_exists('getPathById')) {
        function getPathById($id) {
                $f1 = $id % 10;
                $f2 = floor(($id % 100) / 10);
                $path = '/' . $f1 . '/' . $f2 . '/' . $id;
                return $path;
        }
}

if ( ! function_exists('makeDirsForID')) {
        function makeDirsForID($id, $path) {
                $f1 = $id % 10;
                if (!file_exists($path . '/' . $f1)) {
                        @mkdir($path . '/' . $f1);
                }
                $f2 = floor(($id % 100) / 10);
                if (!file_exists($path . '/' . $f1 . '/' . $f2)) {
                                @mkdir($path . '/' . $f1 . '/' . $f2);
                }
        }
}

Надеюсь, все понятно и помогло:)
1

PHP программирование →  Где использовать исключения в php

В логике


1. Валидация данных: иными словами ошибка входных данных, формат поля не тот, поле не заполнено, ошибка уникальности поля — всё это ошибки входных данных, в таких случаях я бросаю эксепшн с перечислением всех полей и ошибок, которые в последствии выводятся пользователю.
2. 404 Документ не найден: Если была запрошена конкретная сущность(например строка из бд) по её индефикатору(и не только), то в случае если её нет — бросается эксепшн, который в последствии превращается в страницу 404.
3. 403 Доступ запрещён: Если была попытка доступа пользователя туда, куда ему нельзя — то кидается эксепшн(в аргументах можно передать почему нету туда доступа), который в последствии превращается в 403.
4. 401 Требуется авторизация: Пользователь запрашивает данные, куда нужна авторизация. Выкидываем эксепшн(в аргументах можем передать Relarm — текст запроса авторизации), а пользователь получает либо запрос на HTTP авторизацию, либо обычную формочку.
5. 301 Редирект: Надо редиректнуть? кидаем эксепшн — в нём передаём куда надо редиректить.

При обработке ошибок php


1. Фатальные ошибки: Тут всё понятно, нету коннекта к бд, или конфиг нельзя прочесть. Просто пишем в лог и покзывем дефейс.
2. Критические ошибки: Например: СМСка не отправляется, файл нельзя залить — кидаем специфичный эксепшн. а в нужных местах(например — подтверждение телефона), обрабатываем его и пишем пользователю то что не можем отправить смс.

При отладке


В режиме дебага использую PHP_Exceptionizer. Позволяет сделать код чище, любой нотис и варнинг превращает в эксепшн, что в свою очередь позволяет их не пропустить. Естествено это включено только в дебаг-режиме.

Рекомендую логировать все «непонятые» эксепшены:

class Controller_Front
{
  // на уровне приложения
  public function execute()
  {
    try {
      ...
        // где то на уровне контроллера
        try {
          ... // тут вызов основнного тела контроллера
            // Захотели мы редиректнуть на хабр.
            throw new Controller_RedirectException('http://habr.ru');
          ...
        } catch (Controller_DataException $e) {
          // Сохраняем ошибки и показывем их в шаблоне
          $this->errors = $e->getErrors();
        }
      ...
    } catch (Controller_RedirectException $e) {
      // Метод, который посылает заголовки
      $this->_processRedirectException($e);
    } catch (Controller_AuthException $e) {
      // Метод, запрашивающий HTTP авторизацию
      $this->_processAuthException($e);
    } catch (Exception $e) {
      // Записывем эксепшн в лог.
      $this->_logException($e);
      // Показывем дефейс.
      $this->_processFatalException($e);
    }
  }
}
0

PHP программирование →  Юнит-тестирование контроллеров Zend Framework

Тестирование Веб-приложений — это комплексная задача, потому что веб-приложение создается из нескольких логических слоев. Модульное тестирование контроллера Zend Framework может быть весьма трудной задачей, особенно для тех, кто слабо знаком с Zend Framework.

Вы можете тестировать свои контроллеры действий используя Zend_Test и/или PHPUnit. Zend_Test позволяет вам имитировать запросы, передавать тестовые данные, контролировать вывод вашего приложения и в целом убедиться в том, что ваш код делает именно то, что должен делать. Вам решать, какой из них использовать. Если вы не можете выбрать один из них, то можете использовать оба. Если вы только знакомитесь с тестированием с помощью Zend_Test, то эта статья будет лучшей точкой старта.

Фреймворк PHPUnit может показаться очень знакомым тем разработчикам, которые пришли из Java. Разработчики PHPUnit черпали вдохновение из JUnit — тестовом фреймворке для платформы Java, поэтому вы будете чувствовать себя как дома при использовании PHPUnit если вам уже приходилось сталкиваться с JUnit или одним из его клонов.

Конечно, никто не запрещает вам использовать системы бок о бок (даже в одном и том же приложении). В конце концов, большинство проектов так и будет использовать.

Использование PHPUnit


app/
    config/
    controllers/
        ExampleController.php
    models/
    views/
lib/
    Zend/
public/
tests/
    controllers/
        AllTests.php
        ExampleControllerTest.php
    lib/
    AllTests.php
    bootstrap.php


Тестовый набор нуждается в некоторой информации об окружении, и обычно эта информация находится в файле bootstrap.php. Самым большим отличием этого файла от одного из из используемых в вашем приложении является то, что Фронт-контроллер не выполняет диспетчеризацию объекта запроса:

tests/bootstrap.php
<?php
/* Start output buffering */
ob_start();

/* Report all errors directly to the screen for simple diagnostics in the dev environment */
error_reporting( E_ALL | E_STRICT );
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/London');

/* Determine the root and library directories of the application */
$appRoot = dirname(__FILE__) . '/..';
$libDir = "$appRoot/lib";
$path = array($libDir, get_include_path());
set_include_path(implode(PATH_SEPARATOR, $path));

define('APPLICATION_PATH', $appRoot . '/app');
define('APPLICATION_ENVIRONMENT', 'dev');

require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();

$front = Zend_Controller_Front::getInstance();
$front->throwExceptions(true);
$front->setParam('noViewRenderer', true);
$front->setParam('env', APPLICATION_ENVIRONMENT);
$front->setRequest(new Zend_Controller_Request_Http());
$front->returnResponse(true);

$router = $front->getRouter();
include APPLICATION_PATH . '/config/routes.php';
$router->addRoutes($routes);
$router->setParams($front->getParams());

$dispatcher = $front->getDispatcher();
$dispatcher->setParams($front->getParams());
$dispatcher->setResponse($front->getResponse());
$router->route($front->getRequest());


Обратите внимание! Отключение помощника ViewRenderer является не обязательным. Однако, вам должно быть известно, что использование класса Zend_Controller_Action_Helper_ViewRenderer может привести к снижению производительности. Подробнее об этом можно прочесть здесь.

Класс PHPUnit_Framework_TestSuite фреймворка PHPUnit позволяет вам организовать тесты в иерархические наборы тестов:

tests/AllTests.php
<?php
require_once dirname(__FILE__) . '/bootstrap.php';
require_once dirname(__FILE__) . '/controllers/AllTests.php';

class AllTests
{
    public static function main()
    {
        $parameters = array();
        PHPUnit_TextUI_TestRunner::run(self::suite(), $parameters);
    }

    public static function suite()
    {
        $suite = new PHPUnit_Framework_TestSuite('My Application');
        $suite->addTest(ControllersAllTests::suite());
        return $suite;
    }
}
AllTests::main();


tests/controllers/AllTests.php
<?php
require_once dirname(__FILE__) . '/ExampleControllerTest.php';

class ControllersAllTests
{
    public static function main()
    {
        PHPUnit_TextUI_TestRunner::run(self::suite());
    }
    public static function suite()
    {
        $suite = new PHPUnit_Framework_TestSuite('My Application - Controllers');
        $suite->addTestSuite('ExampleControllerTestCase');
        return $suite;
    }
}


Написание модульных тестов


Из-за довольно странных причин эта часть не описана в документации. Вот что вам нужно сделать до написания теста:

1. Подключить контроллер, который вы собираетесь тестировать.
2. Расширить контроллер действий (унаследовавшись от него).
3. Сбросить состояние экземпляра фронт-контроллера.
4. Указать путь к тестируемому контроллеру действий.
5. Установить объекты Запроса и Ответа.
6. Создать экземпляр тестируемого объекта.

Пример:
tests/controllers/ExampleControllerTest.php
<?php
require_once APPLICATION_PATH . '/controllers/ExampleController.php';

class ExampleControllerTest extends ExampleController
{
    public function __construct($url = null)
    {
        $front = Zend_Controller_Front::getInstance();
        $front->resetInstance();
        $front->setControllerDirectory(APPLICATION_PATH . '/controllers');
        $front->setRequest(new Zend_Controller_Request_Http($url));
        $front->setResponse(new Zend_Controller_Response_Http());
        parent::__construct($front->getRequest(), $front->getResponse());
    }
}


Вся магия происходит внутри класса ExampleControllerTest. Он делает так, что контроллер действий думает, что был вызван фронт-контроллером в цикле диспетчеризации. Единственный путь сделать это — создание экземпляра контроллера действий без диспетчеризации запроса. Получение экземпляра контроллера действий дает вам больше контроля и гибкости, особенно при тестировании веб-сервисов.

А теперь пришло время создать наш первый тестовый набор. Тестовый набор это класс, наследуемый от PHPUnit_Framework_TestCase, содержащий тестовые методы, определяемые по префиксу «test» в названии метода.

require_once APPLICATION_PATH . '/controllers/ExampleController.php';

class ExampleControllerTest extends ExampleController
{
    ...
}

class ExampleControllerTestCase extends PHPUnit_Framework_TestCase
{
    public function testDefaultAction()
    {
        $controller = new ExampleControllerTest();
        $isDispatched = $controller->indexAction();

        $this->assertTrue($isDispatched);
    }

    public function testFirstAction()
    {
        $url = 'http://localhost/example/first';
        $controller = new ExampleControllerTest($url);
        $controller->firstAction();
        $errorMsg = $controller->getRequest()->getParam('error_message', null);

        $this->assertEquals(null, $errorMsg);
    }

    public function testGetParameterName()
    {
        $url = 'http://localhost/example/first/fed';
        $controller = new ExampleControllerTest($url);
        $name = $controller->getRequest()->getParam('name', null);

        $this->assertEquals('fed', $name);
    }

    public function testGetNameMethod()
    {
        $url = 'http://localhost/example/first/fed';
        $controller = new ExampleControllerTest($url);
        $name = $controller->getName();
        $this->assertEquals('fed', $name);
    }
}

Запуск тестов



federico@tests$ phpunit AllTests
PHPUnit 3.3.8 by Sebastian Bergmann.
.....
Time: 0 seconds
OK (4 tests, 4 assertions)


Если тестирование завершится неудачно, то вы увидите подробную информацию о проваленном тесте. По желанию, вы можете подключить Phing в Hudson и автоматизировать выполнение этой задачи. Если есть вопросы — обращайтесь.
0

PHP программирование →  Как работает rand?

Столкнулся с задачкой генерации логинов. Недолго думая была написана такая функция:


private function _get_login() {
       
        $login = "";                           
        for( $i=0; $i<=9; $i++ ) {

                $login .= chr( rand( 97, 122 ) );
        }
        return $login;
}
 


Которая по моему скромному мнению должна была генерировать уникальные логины, которые живому человеку придумать тяжело. Упор ставился именно на уникальность.
Если посчитать, количество таких логинов примерно 141167095653376. Логины генерировались и вставлялись в БД. Каково же было моё удивление когда после генерации примерно 1000 логинов посыпались ошибки добавления в базу при срабатывании констрейнтов не уникальности данных. Причем ошибки не единичные, а десятки логинов подряд вылетали. Начал исследовать — выяснилось эта функция действительно генерирует повторяющиеся логины=\. Как такое может быть, что бы последовательности из 10 случайных чисел совпадали так часто? Ответа на этот вопрос так и не нашел. Перешел на использование функции mt_rand(), которая работает в 4 раза быстрее обычной rand(), имеет какие-то известные гарантированные характеристики работы(в отличии от rand()) и добавил элементарную проверку.
Получилось так:


private function _get_login() {
       
       
        $done = false;
        while( !$done ) {
               
                $login = "";                           
                for( $i=0; $i<=9; $i++ ) {

                        $login .= chr( mt_rand( 97, 122 ) );
                }
                $sql = "SELECT count(*) FROM users WHERE login='$login'";
                if($this->db->fetchRow( $sql ) == 0)
                        $done = true;
        }
       
        return $login;
}
 


Может у вас будут идеи по усовершенствованию алгоритма генерации логинов что бы они удовлетворяли следующим условиям:
-более-менее удобочитаемы, а не что-то невнятное вида qlgkakxwci
-более-менее уникальные — что-то типа qlgkakxwci =)

Спасибо за внимание.
1

PHP программирование →  Пишем веб-сервис с использованием протокола SOAP

В главных ролях:
— фреймворк CodeIgniter
— протокол SOAP
— методы getCategories() и getVideos($params = array()) — придуманы для примера
— сайт www.videobox.su используется просто, как заглушка, просто не хотел писать yourdomain.com

Для чего нам нужен SOAP


У нас есть ресурс с определенными данными, например, это будет видео ресурс. Мы хотим дать возможность другим ресурсам тянуть данные с нашего сайта. Было бы хорошо дать возможность сторонним программистам вызывать наши методы. Именно с вызовом удаленных процедур нам поможет SOAP.

Структура сей системы:

— Клиент
— Сервер

Пишем сервер


Мы хотим отдать на доступ два метода getCategories(), который будет возвращать список всех категорий нашего сайта и getVideos($params = array()) — он будет отдавать список видео с информацией в зависимости от входящих параметров $params.

Для начала нам необходимо создать WSDL документ, который опишет два наших метода (имеа методов, входящие данные и возвращаемые данные), по сути это файл в обычном XML формате.
Назовем наш файл webservice.wsdl и положим его по адресу http://videobox.su/webservice/webservice.wsdl
<?xml version ='1.0' encoding ='UTF-8' ?>
<definitions name='webservice'
targetNamespace='uri:webservice'
xmlns:tns='uro:webservice'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns='http://schemas.xmlsoap.org/wsdl/'>

<types>
<!-- описываем тип данных ArrayOfParams, т.к. просто входящим параметром данные типа Array SOAP принимать не умеет -->
        <schema targetNamespace="http://example.com/stockquote/schema" xmlns="http://www.w3.org/2000/10/XMLSchema">
                <complexType name="ArrayOfParams">
                        <complexContent>
                                <restriction base="soapenc:Array">
                                        <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
                                </restriction>
                        </complexContent>
                </complexType>
        </schema>
</types>
<message name='getVideosRequest'>
        <part name='params' type='xsd:ArrayOfParams'/>
</message>
<message name='getVideosResponse'>
        <part name='Result' type='xsd:Array'/>
</message>
<!-- т.к. входящих параметров для метода getCategories() нет, мы не описываем Request -->
<message name='getCategoriesResponse'>
        <part name='Result' type='xsd:Array'/>
</message>
<portType name='webservicePortType'>
        <operation name='getVideos'>
                <input message='tns:getVideosRequest'/>
                <output message='tns:getVideosResponse'/>
        </operation>
        <operation name='getCategories'>
                <input message='tns:getCategoriesRequest'/>
                <output message='tns:getCategoriesResponse'/>
        </operation>
</portType>
<binding name='webserviceBinding' type='tns:webservicePortType'>
  <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
  <operation name='getVideos'>
    <soap:operation soapAction='urn:webservice-video#getVideos'/>
    <input>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
  <operation name='getCategories'>
    <soap:operation soapAction='urn:webservice-video#getCategories'/>
    <input>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </input>
    <output>
      <soap:body use='encoded' namespace='urn:webservice-video' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
</binding>
<service name='webserviceService'>
        <port name='webservicePort' binding='webserviceBinding'>
<!-- URL к нашему серверу -->
                <soap:address location='http://videobox.su/webservice/'/>
        </port>
</service>
</definitions>


Создадим контроллер, который и будет являться нашим сервером.
<?
class Webservice extends Controller{
        function __construct(){
                parent::Controller();
                $this->load->model("video");
                $this->load->model("category");

        }
        function index(){
                function getVideos($params) {
                        $CI = &get_instance ();
                        $videos = array();
//проверка входящих данных
                        if(!is_array($params) || sizeof($params) == 0) {
                                throw new SoapFault("Server:", '$params' . " has wrong format. Can be Array();");
                        }
                        else {
                                return $CI->video->getVideo($params); // выборка данных по видео, здесь можно описать свой код, для краткости сделан вызов из модели
                        }

                }
                function getCategories() {
                        return $CI->category->getAll();  // выборка данных по категориям, здесь можно описать свой код, для краткости сделан вызов из модели
                }

                ini_set("soap.wsdl_cache_enabled", "0"); // отключение кеширования wsdl файла
                $server = new SoapServer("http://videobox.su/webservice/webservice.wsdl?" . rand()); // случайное число добавляем для дебага, т.к. wsdl файл сразуже кешируется и не всегда есть доступ к php.ini или к функции ini_set для отключения кеширования на кремя дебага
                $server->addFunction("getVideos");
                $server->addFunction("getCategories");
                $server->handle();
        }

?>

Наш сервер готов и доступен по адресу http://videobox.su/webservice/.

Пишем клиент


Клиент это та, часть, которая создается сторонними разработчиками с использованием методов, которые мы отдали для использования.

Опять же, создаем контроллер Webserviceclient (если клиент использует CodeIgniter) или не создаем, а а просто используем код, который описан в методе контроллера index(). В любом случае он будет доступен там, где вы его создали.

<?
class Webserviceclient extends Controller{
  function __construct(){
      parent::Controller();
  }
 
        function index(){
                try {
                        $client = new SoapClient("http://videobox.su/webservice/webservice.wsdl?" . rand(),
                                                                                array(
                                                                                        "trace"      => 1,
                                                                                        "exceptions" => 0
                                                                                )
                                                                        );//второй параметр необходим для отладки, является не обязательным
                $params = array(
                        "vid" => 64, //выбираем видео с ID = 64
                );
                print "<pre>";
                print_r($client->getVideos($params)); // вызов метода сервера на выборку данных по видео
                //print "Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n
"; // показать запрос к серверу (работает при включенном дебаге), кому интересно посмотреть на XML - раскомментировать
                //print "
Answer:\n".htmlspecialchars($client->__getLastResponse())."\n
"; // показать ответ сервера (работает при включенном дебаге), кому интересно посмотреть на XML - раскомментировать
                print_r($client->getCategories()); // вызов метода сервера на выборку доступных категорий
                //print "
Request :\n".htmlspecialchars($client->__getLastRequest()) ."\n
";
                //print "
Answer:\n".htmlspecialchars($client->__getLastResponse())."\n
";
                print "
</pre>";
                }
                catch (Exception $e){
                        print $e;
                        echo 'Error Caught';
                }
        }
 
}
?>


В результате мы получим вывод двух массивов данных или в чем придумаете выдачу данных в своей реализации.

Статья была написана в качестве примера, т.к. в интернете не было найдено ничего толкового, а именно были описаны абстрактные примеры, которые трудно соединить в систему, так же сложно было найти, как передать массив в качестве параметра:)
0

PHP программирование →  Удаление коротких слов

В повседневной жизни иногда пирходится удалять короткие слова из текстов
function deleteShortWords($text, $word_lenght = 3) {
                return preg_replace('/( |^)[a-zа-я]{1,' . $word_lenght . '}( |$)/isu', ' ', $text);
        }

Вторым параметром передается количество символов в слове.
0

PHP программирование →  Преобразовать слово в URL

Я уже писал о маленькой полезности для транслитерации слов.
Сегодня у нас в гостях фунция, которая умеет делать из русских слов ЧПУ линки.

function word2URL($text) {
                $text = translit($text); // здесь запользовали функцию транслитерации
                $good_liters= '#[^-a-zA-Z0-9 _]#';
                $text = strtolower(trim(preg_replace($good_liters, '', $text)));
                return preg_replace('#[-_ ]+#', '-', $text);
        }
0

PHP программирование →  Установка ORM Doctrine на Codeigniter (перевод на русский)

Предисловие:
На хабре была описана Правильная интеграция Doctrine в CodeIgniter. Она то, казалось бы, и правильная, но последняя строка мне не очень понравилась: UPD2: в config/autoload.php обязательно надо выключить «database» из списка загружаемых библиотек. Получается, что с БД, при подключенном Doctrine мы работать не сможем.

Скачать Doctrine


В первую очередь, необходимо скачать последнюю версию Doctrine. И положить в папку system/database.
Для линуксоидов:
$ cd system/database
$ svn co http://svn.phpdoctrine.org/branches/0.10/lib doctrine
$ cd ..

// If you use svn in your project you can set Doctrine
// as an external so you receive bug fixes automatically from svn
$ svn propedit svn:externals database

// In your favorite editor add the following line
// doctrine http://svn.phpdoctrine.org/branches/0.10/lib

Установка Doctrine


Конфигурировать доктрин мы будем в файле system/application/config/database.php. Для этого нам необходимо открыть его в любимом редакторе. А линуксоидам сделать следующее:
$ vi application/config/database.php


Далее находим строку:
$db['default']['cachedir'] = "";

И ниже дописываем:

// Create dsn from the info above
$db['default']['dsn'] = $db['default']['dbdriver'] .
                        '://' . $db['default']['username'] .
                        ':' . $db['default']['password'].
                        '@' . $db['default']['hostname'] .
                        '/' . $db['default']['database'];

// Require Doctrine.php
require_once(realpath(dirname(__FILE__) . '/../..') . DIRECTORY_SEPARATOR . 'database/doctrine/Doctrine.php');

// Set the autoloader
spl_autoload_register(array('Doctrine', 'autoload'));

// Load the Doctrine connection
Doctrine_Manager::connection($db['default']['dsn'], $db['default']['database']);

// Load the models for the autoloader
Doctrine::loadModels(realpath(dirname(__FILE__) . '/..') . DIRECTORY_SEPARATOR . 'models');


Далее подключаем файл application/config/database.php в свой фронт контроллер это файл index.php в корне вашего проекта, его нужно открыть любимым редактором.
Линуксоидам сделать так:
$ cd ..
$ vi index.php

Меняем две последних строчки кода на:
require_once APPPATH.'config/database.php';
require_once BASEPATH.'codeigniter/CodeIgniter'.EXT;

Установка Comand Line интерфейса


Создайте файл system/application/doctrine (без расширения). Линуксоидам:
$ vi system/application/doctrine

Поместите туда следующий код:
<?php
require_once('config/database.php');

// Configure Doctrine Cli
// Normally these are arguments to the cli tasks but if they are set here the arguments will be auto-filled
$config = array('data_fixtures_path'  =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/fixtures',
                'models_path'         =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/models',
                'migrations_path'     =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/migrations',
                'sql_path'            =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/sql',
                'yaml_schema_path'    =>  dirname(__FILE__) . DIRECTORY_SEPARATOR . '/schema');

$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);

Далее создаем папки для нужд и испражнений Doctrine.
system/application/fixtures
system/application/migrations
system/application/schema
system/application/sql

TODO линуксоидам:
// Create directory for your yaml data fixtures files
$ mkdir system/application/fixtures

// Create directory for your migration classes
$ mkdir system/application/migrations

// Create directory for your yaml schema files
$ mkdir system/application/schema

// Create directory to generate your sql to create the database in
$ mkdir system/application/sql


Наш Comand Line интерфейс готов. Дальше всеравно прийдется лезть в командную строку:) Для того что бы просмотреть все, что умеет Doctrine, необходимо запустить shell скрипт:
$ cd system/application
$ ./doctrine
Doctrine Command Line Interface

./doctrine build-all
./doctrine build-all-load
./doctrine build-all-reload
./doctrine compile
./doctrine create-db
./doctrine create-tables
./doctrine dql
./doctrine drop-db
./doctrine dump-data
./doctrine generate-migration
./doctrine generate-migrations-db
./doctrine generate-migrations-models
./doctrine generate-models-db
./doctrine generate-models-yaml
./doctrine generate-sql
./doctrine generate-yaml-db
./doctrine generate-yaml-models
./doctrine load-data
./doctrine load-dummy-data
./doctrine migrate
./doctrine rebuild-db
$

Для фанатов видоуса необходимо запустить скрипт через php
> php.exe doctrine

Использование Doctrine


Для начала работы создадим yaml схему.
---
User:
  columns:
    username:
      type: string(255)
    password:
      type: string(255)

И положим его в папку system/application/schema. Следующая команда сгенерит нам модели (php классы для работы с данными) из yaml файлов и положит их в system/application/models
$ ./doctrine generate-models-yaml
generate-models-yaml - Generated models successfully from YAML schema

Что бы посмотреть, что нам нагенерил Doctrine откроем файл system/application/models/generated/BaseUser.php
<?php

/**
* This class has been auto-generated by the Doctrine ORM Framework
*/

abstract class BaseUser extends Doctrine_Record
{
  public function setTableDefinition()
  {
    $this->setTableName('user');
    $this->hasColumn('username', 'string', 255, array (
));
    $this->hasColumn('password', 'string', 255, array (
));
  }
}

// Add custom methods to system/application/models/User.php

<?php

/**
* This class has been auto-generated by the Doctrine ORM Framework
*/

class User extends BaseUser
{
  public function setPassword($password)
  {
    $this->password = md5($password);
  }
}

/**
* This class has been auto-generated by the Doctrine ORM Framework
*/

class UserTable extends Doctrine_Table
{
  public function retrieveAll()
  {
    $query = new Doctrine_Query();
    $query->from('User u');
    $query->orderby('u.username ASC');

    return $query->execute();
  }
}

Создадим тестовые данные для загрузки в наше приложение. Для этого необходимо создать файл system/application/fixtures/users.yml. И в нем прописать данные:
---
User:
  jwage:
    username: jwage
    password: test

Командой build-all-reload мы пересоздадим нашу БД и модели
$ ./doctrine build-all-reload
build-all-reload - Are you sure you wish to drop your databases? (y/n)
y
build-all-reload - Successfully dropped database named: "jwage_codeigniter"
build-all-reload - Generated models successfully from YAML schema
build-all-reload - Successfully created database named: "jwage_codeigniter"
build-all-reload - Created tables successfully
build-all-reload - Data was successfully loaded

Для того. что бы убедиться, что все сделано правильно откройте/создайте system/application/views/welcome_message.php и добавьте следующий код:
$user = new User();
$user->username = 'zYne-';
$user->setPassword('password');
$user->save();

$userTable = Doctrine::getTable('User');
$user = $userTable->findOneByUsername('zYne-');

echo $user->username; // prints 'zYne-'

$users = $userTable->retrieveAll();

echo $users->count(); // echo '2''
foreach ($users as $user)
{
  echo $user->username;
}
0

PHP программирование →  Функция для транслитерации слов

Необходимо было написать функцию транслитерации кирилицы в латиницу. Пошарился по интернету, нашел много неоптимальных говнорешений. Написал свое мегарешение:)

При транслитерации использовался стандарт ISO 9 — 1995 (Transliteration of Slavic Cyrillic characters into Latin characters).


( Читать дальше )
0

PHP программирование →  HTML парсер

Мое мнение, что о таких программах нужно рассказывать и ними нужно делиться. Делюсь:)

На днях нужно было распарсить один сайт, с регулярными выражениями возиться не очень хотелось, скажем, возиться вообще ни с чем не хотелось:)) Хотелось инструмент, который будет простым в использовании и качественно выполнять поставленную задачу.


( Читать дальше )
2
←  сюда    туда  →
1 2 3