Качаем Development package xampp и исходники модуля memcache для php c http://pecl.php.net/package/memcache.
Распаковываем:
debian:tar xvfz xampp-linux-devel-1.7.3a.tar.gz -C /opt
debian:/home/leon/Downloads# exit
exit
leon@debian:~/Downloads$ tar xzf memcache-3.0.5.tgz
leon@debian:~/Downloads$ cd memcache-3.0.5
leon@debian:~/Downloads/memcache-3.0.5$ sudo /opt/lampp/bin/phpize
Configuring for:
PHP Api Version: 20090626
Zend Module Api No: 20090626
Zend Extension Api No: 220090626
Cannot find autoconf. Please check your autoconf installation and the
$PHP_AUTOCONF environment variable. Then, rerun this script.
leon@debian:~/Downloads/memcache-3.0.5$ sudo apt-get install autoconf
...
leon@debian:~/Downloads/memcache-3.0.5$ sudo /opt/lampp/bin/phpize
Configuring for:
PHP Api Version: 20090626
Zend Module Api No: 20090626
Zend Extension Api No: 220090626
leon@debian:~/Downloads/memcache-3.0.5$
leon@debian:~/Downloads/memcache-3.0.5$ ./configure --enable-memcache --with-php-config=/opt/lampp/bin/php-config
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for a sed that does not truncate output... /bin/sed
checking for cc... no
checking for gcc... no
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details.
leon@debian:~/Downloads/memcache-3.0.5$ sudo apt-get install gcc
...
leon@debian:~/Downloads/memcache-3.0.5$ ./configure --enable-memcache --with-php-config=/opt/lampp/bin/php-config
...
checking for the location of zlib... configure: error: memcache support requires ZLIB. Use --with-zlib-dir=<DIR>
to specify prefix where ZLIB include and library are located
...
leon@debian:~/Downloads/memcache-3.0.5$ sudo apt-get install zlib1g-dev
...
leon@debian:~/Downloads/memcache-3.0.5$ ./configure --enable-memcache --with-php-config=/opt/lampp/bin/php-config
leon@debian:~/Downloads/memcache-3.0.5$ sudo apt-get install make
leon@debian:~/Downloads/memcache-3.0.5$ make
leon@debian:~/Downloads/memcache-3.0.5$ sudo make install
...
Installing shared extensions: /opt/lampp/lib/php/extensions/no-debug-non-zts-20090626/
leon@debian:~/Downloads/memcache-3.0.5$ sudo nano /opt/lampp/etc/php.ini
Некоторые пакеты с более новыми версиями для Lenny доступны из репозитория backports.
leon@debian:~$ su
Пароль:
debian:/home/leon# nano /etc/sudoers
Добавляем в файл строку:
leon ALL=(ALL) ALL
Этим мы позволяем пользователю пользоваться командой sudo.
debian:/home/leon# exit
exit
leon@debian:~$ sudo nano /etc/apt/sources.list
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for leon:
Добавляем репозиторий в список: deb http://www.backports.org/debian lenny-backports main contrib non-free
Изменение размера изображения без искажений.
Свойство clip позволяет задать размеры абсолютно позиционированного элемента img.
Элемент должен быть видимым (visible).
Если используется PHP5 (>= 5.3.2) и PHPUnit возможно тестирование защищенных методов класса с помощью reflection. При этом методы становятся public перед запуском тестов.
protected static function getMethod($name)
{
$class = new ReflectionClass(MyClass::class);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method;
}
public function testFoo()
{
$foo = self::getMethod('foo');
$obj = new MyClass();
$foo->invokeArgs($obj, [...]);
...
}
Шаблон Facade (Фасад) — Шаблон проектирования, позволяющий скрыть сложность системы путем сведения всех возможных внешних вызовов к одному объекту, делегирующему их соответствующим объектам системы.
class Foo {
public function bar() {
echo "Foo::bar()\n";
}
}
class Bar {
public function foo() {
echo "Bar::foo()\n";
}
}
class Facade {
protected $_foo = null;
protected $_bar = null;
public function __construct() {
$this->_foo = new Foo();
$this->_bar = new Bar();
}
public function bar() {
$this->_foo->bar();
}
public function foo() {
$this->_bar->foo();
}
}
$facade = new Facade();
$facade->foo();
$facade->bar();
pwd (англ. print working directory — напечатать рабочий каталог) — консольная утилита в UNIX-подобных системах, которая выводит полный путь от корневого каталога к текущему рабочему каталогу.
Предварительные действия:
1. Распаковываем архив gcc в $LFS/sources
2. Переходим в каталог $LFS/sources/gcc-4.5.1
3. Распаковываем архивы gmp, mpc и mpfr в каталог gcc-4.5.1
4. Создаем каталог $LFS/sources/gcc-build (../gcc-build)
5. Переходим в gcc-build
--disable-decimal-float, --disable-threads, --disable-libmudflap,
--disable-libssp, --disable-libgomp
Отключаем поддержку функций в которых нет необходимости.
Using - - disable- shared means that the libgcc_ eh. a file isn't created and installed. The Glibc package
depends on this library as it uses - lgcc_ eh within its build system. This dependency can be satisfied by creating a
symlink to libgcc. a, since that file will end up containing the objects normally contained in libgcc_ eh. a:
ln -vs libgcc.a `$LFS_TGT-gcc -print-libgcc-file-name | \
sed 's/libgcc/&_eh/'`
Я собираю на Debian на Intel P4 (Oracle VirtualBox 3.2.10 под Windows XP SP3), поэтому в ./configure для binutils я добавил опцию --build='i386-pc-linux'
--target=$LFS_TGT
--prefix=/tools
Готовим к установке в /tools
--disable-nls
Запрещаем интернационализацию, оно нам не надо.
--disable-werror
Запрещаем остановку сборки при warning компилятора хост-системы.
Наша задача создать абсолютно независимое от хост-системы окружение, для этого создаем .bashrc:
cat > ~/.bashrc << "EOF"
set +h
umask 022
LFS=/mnt/lfs
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu
PATH=/tools/bin:/bin:/usr/bin
export LFS LC_ALL LFS_TGT PATH
EOF
set +h
Запрещаем кеширование путей к исполняемым файлам, шелл всегда будет проверять пути в переменной PATH и находить все только что скомпилированные инструменты в каталоге tools. Таким образом мы избежим использования инструментов хост-системы.
umask 022
Все вновь созданные файлы доступны для записи только владельцем, а для чтения и запуска кем угодно.
LFS=/mnt/lfs
Переменная указывает путь к каталогу к которому монтируется раздел будущей системы.
# The Perl/CGI functions have the
# additional property of "stability"
# when used in reentrant forms.
# The values of the HTML elements are
# set according to the incoming
# parameter values for those elements.
# The versions below are not stable.
$ref = "x.php";
<a href="<?php echo $ref?>">yy</a>
<input type=text name=yy size=5>
<input type=password name=yy size=5>
<textarea name=yy cols=5 rows=2>
</textarea>
<input type="submit" value=yy>
<input type="button"
name="xx" value="yy"
onclick="submit()">
<select name="xx" size="4">
<?php
$labels = array(0=>'a',1=>'q',2=>'x');
foreach (range(0,2) as $_)
echo "<option value='$_'>",
$labels[$_];
?>
</select>
$a = array('xx','yy','zz');
foreach ($a as $_)
echo "<input type=radio
name=nn value='$_'>$_<br>";
$labels = array('xx'=>'L1','yy'=>'L2');
foreach (array_keys($labels) as $_)
echo "<input type=checkbox
name=nn value='$_'>",
$labels[$_];
<table>
<tr>
<td>a</td><td>b</td>
</tr>
<tr>
<td>x</td><td>y</td>
</tr>
</table>
urlencode
use URI::Escape;
uri_escape($val)
uri_unescape($val)
Для начала посмотрим реализацию шаблона Singletone на php:
class Singleton
{
private static $uniqueInstance = NULL;
protected function __construct() {}
private final function __clone() {}
public static function getInstance()
{
if (self::$uniqueInstance === NULL) {
self::$uniqueInstance = new Singleton;
}
return self::$uniqueInstance;
}
}
Этот шаблон гарантирует, что код не будет доступен в приложении, иначе как через метод getInstance(). И клиент не сможет создать объект используя методы new или __clone.
class Client
{
public function doSomething()
{
$singleton = Singleton::getInstance();
// ...
}
}
Очевидно, что невозможно написать тест для метода doSomething() без вызова getInstance(). Это значит, что мы не сможем создать новый объект для каждого из группы тестов и мы не сможем избежать побочных эффектов при тестировании.
Ниже приведены три варианта решения задачи:
Внедрение зависимости (Dependency Injection).
class Client
{
public function doSomething(Singleton $singleton = NULL)
{
if ($singleton === NULL) {
$singleton = Singleton::getInstance();
}
// ...
}
}
Теперь вместо того, чтобы вызывать метод getInstance() мы можем подменить объект
класса Singletone mock-объектом или заглушкой (Stub).
class ClientTest extends PHPUnit_Framework_TestCase
{
public function testSingleton()
{
$singleton = $this->getMock(
'Singleton', /* name of class to mock */
array(), /* list of methods to mock */
array(), /* constructor arguments */
'', /* name for mocked class */
FALSE /* do not invoke constructor */
);
// ... configure $singleton ...
$client = new Client;
$client->doSomething($singleton);
// ...
}
}
Альтернативная реализация Singletone.
Вместо того чтобы модифицировать клиентский код для облегчения тестирования, мы может немного изменить реализацию одиночки, добавив дополнительный метод для обнуления объекта.
class Singleton
{
private static $uniqueInstance = NULL;
protected function __construct() {}
private final function __clone() {}
public static function getInstance()
{
if (self::$uniqueInstance === NULL) {
self::$uniqueInstance = new Singleton;
}
return self::$uniqueInstance;
}
public static function reset() {
self::$uniqueInstance = NULL;
}
}
Singleton с тестовым контекстом.
class Singleton
{
private static $uniqueInstance = NULL;
public static $testing = FALSE;
protected function __construct() {}
private final function __clone() {}
public static function getInstance()
{
if (self::$uniqueInstance === NULL ||
self::$testing) {
self::$uniqueInstance = new Singleton;
}
return self::$uniqueInstance;
}
}
Выставив Singleton::$testing = TRUE; мы гарантируем, что метод getInstance() будет создавать новый объект при каждом вызове.
Что делать, если хотим хотим добавить новую строку в список, но не хотим при этом его заново генерировать? На самом деле эту задачу можно решить разными способами, но я выбрал следующий. Имеем следующие данные и директивы:
// Объект data = { value: 'myVal' }; // Вставить в ячейку таблицы значение объекта // !!! В PURE мы можем использовать селекторы CSS для доступа к элементам !!! // Точно также, как в Jquery и это очень хорошая новость var directive = { 'td': 'value' };
Создаем шаблон-таблицу (список):
<table> <tr> <td></td> </tr> </table>
Выбираем tr как фрагмент шаблона, который хотим использовать. Используем метод compile для преобразования шаблона в функцию.
// Как параметр foo будет принимать данные для вставки в шаблон // а возвращать уже готовый html var foo = $('tr').compile(directive); // !!! Jquery !!! // Добавляем новую строку в таблицу $('table').append(foo(data))
.live() позволяет прикрепить обработчик события к элементу с заданным селектором в любом случае, был ли он в DOM при загрузке страницы или будет добавлен в будущем
С помощью этого инструмента логика и представление будут полностью разделены. Работает как сам, так и в связке с популярными javascript фреймворками: dojo, DomAssistant, jQuery, Mootools, Prototype, Sizzle и Sly
Кодирование и декодирование JSON в javascript. Страница проекта на code.google.com
Использование:
var thing = {plugin: 'jquery-json', version: 2.2}; var encoded = $.toJSON(thing); //'{"plugin":"jquery-json","version":2.2}' var name = $.evalJSON(encoded).plugin; //"jquery-json" var version = $.evalJSON(encoded).version; // 2.2
1. Загружаемся с liveCD или загрузочной флешки, сделать ее можно с помощью http://unetbootin.sourceforge.net/. 2. Запускаем gnome-terminal 3. Изучаем таблицу разделов sudo fdisk -l видим что-то вроде этого ... /dev/sda1 29 8369 66999082+ 83 Linux /dev/sda2 * 8370 13995 45190845 7 HPFS/NTFS /dev/sda3 13996 14593 4803435 5 Extended /dev/sda5 13996 14593 4803403+ 82 Linux swap / Solaris
и монтируем наш Linux-раздел ...
sudo mount /dev/sda1 /mnt sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc
4. Меняем корневой раздел
sudo chroot /mnt
chroot — операция изменения корневого каталога в Unix-подобных операционных системах. Программа, запущенная с изменённым корневым каталогом, будет иметь доступ только к файлам, содержащимся в данном каталоге. Поэтому, если нужно обеспечить программе доступ к другим каталогам или файловым системам (например, /proc), нужно заранее примонтировать в целевом каталоге необходимые каталоги или устройства.
После этого sudo больше не требуется
5. Устанавливаем grub grub-install /dev/sda
6. Возвращаемся в корневой раздел liveCD отмонтируем разделы и перезагружаемся: exit sudo umount /mnt/dev sudo umount /mnt/proc sudo umount /mnt sudo reboot
Для редактирования меню GRUB существует очень удобная утилита Grub Customizer. Установить ее можно так: sudo add-apt-repository ppa:danielrichter2007/grub-customizer sudo apt-get update sudo apt-get install grub-customizer
Этот хелпер используется для встраивания шаблона с собственной областью видимости переменных. В основном полезно для многократного использования фрагментов шаблона, при этом можно не беспокоиться по поводу конфликтов имен. Дает возможность создавать модульные шаблоны (скрипты вида).
Предположим, что у нас есть таблица Entity. В нашем приложении мы вводим две сушности User и Group, которые обе являются Entity и их данные хранятся в одной таблице. Таблица (класс) Entity имеет атрибут type, определяющий, относится объект (запись) к классу User или Group. Мы определяем, что для User type равен 1, а для Group - 2.
Все что нам нужно - это создать 3 записи и вызвать метод Doctrine_Table::setSubclasses() в родительском классе:
// models/Entity.php
class Entity extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('name', 'string', 30); $this->hasColumn('username', 'string', 20); $this->hasColumn('password', 'string', 16); $this->hasColumn('created_at', 'timestamp'); $this->hasColumn('update_at', 'timestamp');
Диаграмма классов, показывающая наследование двух подклассов от одного суперкласса Обобщение (Generalization) показывает, что один из двух связанных классов (подтип) является более частной формой другого (надтипа), который называется обобщением первого. На практике это означает что любой экземпляр подтипа является также экземпляром надтипа. Например: животные — супертип млекопитающих, которые в свою очередь супертип приматов и так далее. Эта взаимосвязь легче всего описывается фразой «А — это Б» (приматы — это млекопитающие, млекопитающие — это животные). Графически генерализация представляется линией с пустым треугольником у супертипа Генерализация также известна как наследование или "is a" взаимосвязь.
Агрегация — это разновидность ассоциации, при отношении между целым и его частями. Как тип ассоциации, агрегация может быть именованной. Агрегация не может включать сразу несколько классов. Агрегация встречается, когда один класс является коллекцией или контейнером других. Причём по умолчанию, агрегацией называют агрегацию по ссылке, т.е. когда время существования содержащихся классов не зависит от времени существования содержащего их класса. Если контейнер будет уничтожен, то его содержимое — нет. Графически агрегация представляется пустым ромбиком на блоке класса и линией, идущей от этого ромбика к содержащемуся классу.
Композиция — более строгий вариант агрегации. Известна также как агрегация по значению. Композиция имеет жёсткую зависимость времени существования экземпляров класса контейнера и экземпляров содержащихся классов. Если контейнер будет уничтожен, то всё его содержимое будет также уничтожено . Графически представляется как и агрегация, но с закрашенным ромбиком.
// 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' => DATA_FIXTURES_PATH, 'models_path' => MODELS_PATH, 'migrations_path' => MIGRATIONS_PATH, 'sql_path' => SQL_PATH, 'yaml_schema_path' => YAML_SCHEMA_PATH, 'generate_models_options' => $options );
$cli = new Doctrine_Cli($config); $cli->run($_SERVER['argv']);
В NetBeans IDE тестовые классы PHPUnit можно создавать в контекстном меню (вызов контекстного меню для файла в дереве проекта). Подробно это описано в документации.
Для запуска тестов проекта NetBeans использует класс NetBeansSuite, который находится в моем случае в каталоге C:\Program Files\NetBeans 6.10 M1\php\phpunit\NetBeansSuite.php. Мы можем переопределить стандартную конфигурацию запуска тестов тремя способами:
1. Файл начальной загрузки (bootstrap file)
2. Файл конфигурации xml
3. Собственный класс расширяющий PHPUnit_Framework_TestSuite
В данном случае интересует вариант 3.
В каталоге с тестами проекта я создал файл MySuite.php
// MySuite.php
require_once 'MyClassATest.php';
require_once 'MyClassBTest.php';
require_once 'MyListener.php';
class MySuite extends PHPUnit_Framework_TestSuite
{
public function setUp()
{
parent::setUp();
echo __METHOD__ . "\n";
}
public function tearDown()
{
parent::tearDown();
echo __METHOD__ . "\n";
}
public static function suite()
{
$suite = new MySuite();
$suite->addTestSuite('MyClassATest');
$suite->addTestSuite('MyClassBTest');
return $suite;
}
public function run(PHPUnit_Framework_TestResult $result = NULL,
$filter = FALSE, array $groups = array(), array $excludeGroups = array(),
$processIsolation = FALSE)
{
if($result == NULL)
{
$result = new PHPUnit_Framework_TestResult();
}
$result->addListener(new MyListener());
parent::run($result, $filter, $groups, $excludeGroups, $processIsolation);
}
}
В настройках проекта необходимо указать, что используем собственный класс и путь к нему. Теперь мы можем вызывать в методах setUp и tearDown все что нам нужно.
Запуск тестового набора ALT - F6 ...
PHPUnit 3.5.0 by Sebastian Bergmann.
MySuite::setUp
MyListener::startTest
MyClassATest::setUp
.MyListener::endTest
MyListener::startTest
MyClassATest::setUp
.MyListener::endTest
MyListener::startTest
MyClassBTest::setUp
IMyListener::endTest
MyListener::startTest
MyClassBTest::setUp
IMyListener::endTest
MySuite::tearDown
Time: 1 second, Memory: 4.00Mb
OK, but incomplete or skipped tests!
Tests: 4, Assertions: 1, Incomplete: 2.
Классы модели наследуют определенный супер-класс. В моем случае это Doctrine_Record.
Для того чтобы можно было создавать тесты классов из контекстного меню (Tools -> Create PHPUnit tests), необходимо создать bootstrap.php.
В настройках проекта указываем bootstrap и указываем, что используем его для генерации классов. Вызов Skeleton Generator PHPUnit также имеет опцию bootstrap.
Таким образом мы инициализируем все автозагрузчики классов.
; Для unix zend_extension=/path/to/xdebug.so ; Для windows zend_extension = "C:\xampp\php\ext\php_xdebug-2.1.0-5.3-vc6.dll" xdebug.remote_enable=1 xdebug.remote_handler=dbgp xdebug.remote_mode=req xdebug.remote_host=127.0.0.1 xdebug.remote_port=9000
При тестировании кода, использующего базу данных, обычно мы хотим чтобы структура базы данных не менялась для каждого теста. Таблицы должны быть пустыми, данные должны соответствовать тестам.
Конечно мы можем написать класс, расширяющий ТestCase, который сделает это автоматически при инициализации, в методе setUp, и в конце, в методе tearDown, но уже существует ряд готовых решений.
Например, в Zend Framework и т.д.
Хорошая новость в том, что PHPUnit имеет механизм добавления слушателей, реагирующих на определенные события.
TestListener
Мы можем использовать интерфейс TestListener PHPUnit для создания класса - обработчика события, который будет работать до и после выполнения каждого теста. Так как мы используем Doctrine сброс базы данных - это очень простая задача: просто создадим в оперативной памяти SQLite базу данных и позволим Doctrine создать таблицы в ней из классов модели нашего приложения. Закрытие соединения приведет к уничтожению этой базы данных, так как она находится в памяти. Это самый простой вариант.
Теперь, как определить использует ли тестовое задание базу данных? Мы конечно же не заинтересованы в бессмысленной трате ресурсов на реинициализацию базы данных. Хорошим решением будет ввод интерфейса, который будут реализовывать наши тестовые задания и который будет проверятся слушателем.
Простая реализация
interface DbTest_Interface
{
}
class DbResetListener implements PHPUnit_Framework_TestListener
{
public function startTest(PHPUnit_Framework_Test $test) {
if($test instanceof DbTest_Interface) {
Doctrine_Manager::connection(new PDO('sqlite::memory:'));
Doctrine::createTablesFromModels();
}
}
public function endTest(PHPUnit_Framework_Test $test, $time) {
if($test instanceof DbTest_Interface) {
Doctrine_Manager::getInstance()
->closeConnection(Doctrine_Manager::connection());
}
}
//Other methods needed for interface but nothing else
public function startTestSuite(PHPUnit_Framework_TestSuite $suite) {}
public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {}
public function addError(PHPUnit_Framework_Test $test,
Exception $e, $time) {}
public function addFailure(PHPUnit_Framework_Test $test,
PHPUnit_Framework_AssertionFailedError $e, $time) {}
public function addIncompleteTest(PHPUnit_Framework_Test $test,
Exception $e, $time) {}
public function addSkippedTest(PHPUnit_Framework_Test $test,
Exception $e, $time) {}
}
Все довольно просто, тестовые задания должны реализовывать интерфейс DbTest_Interface, в противном случае слушатель их проигнорирует.
Чтобы все это использовать мы должны сначала загрузить модель приложения
Doctrine::loadModels('/path/to/models');
И добавить слушатель ...
class AllTests
{
public static function main()
{
$listener = new DbResetListener();
PHPUnit_TextUI_TestRunner::run(self::suite(), array(
'listeners' => array($listener)
));
}
/* other stuff here */
}
Ниже последовательность действий по установке профайлера и отладчика для PHP. 1. Устанавливает пакет разработчика для xampp (XAMPP development package), который содержит необходимые исходники. Предварительно скачиваем его с сайта xampp.
tar xvfz xampp-linux-devel-1.7.3a.tar.gz -C /opt
2. Качаем исходники xdebug c http://www.xdebug.com/, распаковываем и переходим в соотв. директорию. 3. Запускаем phpize
leon@leon-desktop:~/xdebug-2.0.5$ /opt/lampp/bin/phpize Configuring for: PHP Api Version: 20090626 Zend Module Api No: 20090626 Zend Extension Api No: 220090626 Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF environment variable. Then, rerun this script.
Делаем следующее:
sudo apt-get install build-essential
И снова phpize
leon@leon-desktop:~/xdebug-2.0.5$ /opt/lampp/bin/phpize Configuring for: PHP Api Version: 20090626 Zend Module Api No: 20090626 Zend Extension Api No: 220090626 configure.in:3: warning: prefer named diversions configure.in:150: warning: AC_CACHE_VAL(lt_prog_compiler_static_works, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:2019: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:2040: AC_CACHE_CHECK is expanded from... aclocal.m4:3555: AC_LIBTOOL_LINKER_OPTION is expanded from... aclocal.m4:5493: _LT_AC_LANG_C_CONFIG is expanded from... aclocal.m4:5492: AC_LIBTOOL_LANG_C_CONFIG is expanded from... aclocal.m4:2972: AC_LIBTOOL_SETUP is expanded from... aclocal.m4:2952: _AC_PROG_LIBTOOL is expanded from... aclocal.m4:2915: AC_PROG_LIBTOOL is expanded from... configure.in:150: the top level configure.in:150: warning: AC_CACHE_VAL(lt_prog_compiler_pic_works, ...): suspicious cache-id, must contain _cv_ to be cached aclocal.m4:3510: AC_LIBTOOL_COMPILER_OPTION is expanded from... aclocal.m4:7620: AC_LIBTOOL_PROG_COMPILER_PIC is expanded from... configure.in:150: warning: AC_CACHE_VAL(lt_prog_compiler_pic_works_CXX, ...): suspicious cache-id, must contain _cv_ to be cached aclocal.m4:5606: _LT_AC_LANG_CXX_CONFIG is expanded from... aclocal.m4:5605: AC_LIBTOOL_LANG_CXX_CONFIG is expanded from... aclocal.m4:4641: _LT_AC_TAGCONFIG is expanded from... configure.in:3: warning: prefer named diversions configure.in:150: warning: AC_CACHE_VAL(lt_prog_compiler_static_works, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:2019: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:2040: AC_CACHE_CHECK is expanded from... aclocal.m4:3555: AC_LIBTOOL_LINKER_OPTION is expanded from... aclocal.m4:5493: _LT_AC_LANG_C_CONFIG is expanded from... aclocal.m4:5492: AC_LIBTOOL_LANG_C_CONFIG is expanded from... aclocal.m4:2972: AC_LIBTOOL_SETUP is expanded from... aclocal.m4:2952: _AC_PROG_LIBTOOL is expanded from... aclocal.m4:2915: AC_PROG_LIBTOOL is expanded from... configure.in:150: the top level configure.in:150: warning: AC_CACHE_VAL(lt_prog_compiler_pic_works, ...): suspicious cache-id, must contain _cv_ to be cached aclocal.m4:3510: AC_LIBTOOL_COMPILER_OPTION is expanded from... aclocal.m4:7620: AC_LIBTOOL_PROG_COMPILER_PIC is expanded from... configure.in:150: warning: AC_CACHE_VAL(lt_prog_compiler_pic_works_CXX, ...): suspicious cache-id, must contain _cv_ to be cached aclocal.m4:5606: _LT_AC_LANG_CXX_CONFIG is expanded from... aclocal.m4:5605: AC_LIBTOOL_LANG_CXX_CONFIG is expanded from... aclocal.m4:4641: _LT_AC_TAGCONFIG is expanded from...
При этом типе наследования ORM Doctrine создает отдельные таблицы для дочерних классов. При этом каждый класс генерирует таблицы, которые содержат все столбцы (включая и унаследованные). Для того чтобы использовать такой тип наследования, вам необходимо явно вызвать parent::setTableDefinition() у дочерних классов, как показано ниже:
// models/TextItem.php
class TextItem extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('topic', 'string', 100); } }
Теперь давайте создадим модель Comment, расширяющую TextItem, и добавим новый столбец content:
// models/Comment.php
class Comment extends TextItem { public function setTableDefinition() { parent::setTableDefinition();
Это самый простой в использовании тип наследования. Дочерние классы хранять свои данные в тех же таблицах, что и родительские, и имеют те же атрибуты (колонки таблиц).
// models/Entity.php
class Entity extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('name', 'string', 30); $this->hasColumn('username', 'string', 20); $this->hasColumn('password', 'string', 16); $this->hasColumn('created_at', 'timestamp'); $this->hasColumn('update_at', 'timestamp'); } }
Теперь создаем модель User, расширяющую (наследующую) Entity ...
// Контейнер для значений элементов формы var videoIds = []; // Проход по объектам элементов формы с помощью итератора ... $("input[name=videoIds\\[\\]]").each(function () { // ... помещаем значение в контейнер videoIds.push(this.value); }) // Выводим результат, склеивая значения элементов массива alert(videoIds.join(', '));
Объект выступает в качестве шлюза между данными в приложении и в БД. Один объект работает сразу со всеми записями в таблице.
Сочетание SQL-запросов и логики приложения может вызвать достаточно много проблем. Есть разработчики, которые не сильны в SQL, а есть и те, кто в этом преуспел. Администраторы SQL-серверов должны иметь возможность быстро найти SQL-код, чтобы понимать каким образом настраивать и развивать сервера.
Объект шлюза к таблице содержит все запросы SQL для доступа к отдельной таблице или представлению (view): выборка, обновление, вставка, удаление (CRUD). Остальной код, для взаимодействия с БД, обращается к методам объекта шлюза.
Пример: объект шлюза PersonGateway содержит методы для доступа к таблице person в БД. Методы содержат SQL-код для выборки, вставки, обновления и удаления. Объект может содержать специальную выборку, например поиск по компании.
Шаблон проектирования "Адаптер" используется, когда требуется преобразовать объект одного типа в объект другого типа. Использование этого шаблона, как и всех прочих, повышает чистоту кода и возможность его многократного использования.
// Класс для вывода адреса class AddressDisplay { private $addressType; private $addressText;
public function setAddressType($addressType) { $this->addressType = $addressType; }
public function getAddressType() { return $this->addressType; }
public function setAddressText($addressText) { $this->addressText = $addressText; }
public function getAddressText() { return $this->addressText; } }
// Класс адреса электронной почты class EmailAddress { private $emailAddress;
public function getEmailAddress() { return $this->emailAddress; }
public function setEmailAddress($address) { $this->emailAddress = $address; } }
// Адаптер class EmailAddressDisplayAdapter extends AddressDisplay { public function __construct($emailAddr) { $this->setAddressType("email"); $this->setAddressText($emailAddr->getEmailAddress()); } }
// Использование адаптера $email = new EmailAddress(); $email->setEmailAddress("user@example.com");
$address = new EmailAddressDisplayAdapter($email);
Как видно, после реализации шаблона, нам больше нечего беспокоится за то, как EmailAddress преображается в AddressDisplay. И это хорошая новость, особенно если изменится реализация AddressDisplay. Основное преимущество модульного дизайна в том, чтобы иметь возможность менять минимум кода при изменении бизнес-модели приложения или добавлении нового функционала. Важно помнить об этом даже в тривиальных вещах, таких как передача значений от объекта к объекту.
Константный итератор не допускает изменения данных, на которые он ссылается. Можно считать константный итератор указателем на константу. Чтобы получить константный итератор, можно воспользоваться типом const_iterator, предопределенным в различных контейнерах.
... если в контейнере итератор ссылается на первый элемент данных, то реверсивный итератор ссылается на последний ...
$dbh = new PDO('mysql:dbname=test;host=localhost', $username, $password);
// let's have exceptions instead of silence.
// other modes: PDO_ERRMODE_SILENT (default - check $stmt->errorCode()
// and $stmt->errorInfo()) PDO_ERRMODE_WARNING (php warnings)
$dbh->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION);
// one-shot query
$dbh->exec("create table test(name varchar(255) not null primary key,
value varchar(255));");
// insert some data using a prepared statement
$stmt = $dbh->prepare("insert into test (name, value) values (:name, :value)");
// bind php variables to the named placeholders in the query
// they are both strings that will not be more than 64 chars long
$stmt->bindParam(':name', $name, PDO_PARAM_STR, 64);
$stmt->bindParam(':value', $value, PDO_PARAM_STR, 64);
// insert a record
$name = 'Foo';
$value = 'Bar';
$stmt->execute();
// and another
$name = 'Fu';
$value = 'Ba';
$stmt->execute();
// more if you like, but we're done
$stmt = null;
// get some data out based on user input
$what = $_GET['what'];
$stmt = $dbh->prepare('select name, value from test where name=:what');
$stmt->bindParam('what', $what);
$stmt->execute();
// get the row using PDO_FETCH_BOTH (default if not specified as parameter)
// other modes: PDO_FETCH_NUM, PDO_FETCH_ASSOC,
// PDO_FETCH_OBJ, PDO_FETCH_LAZY, PDO_FETCH_BOUND
$row = $stmt->fetch();
print_r($row);
$stmt = null;
// get all data row by row
$stmt = $dbh->prepare('select name, value from test');
$stmt->execute();
while ($row = $stmt->fetch(PDO_FETCH_ASSOC)) {
print_r($row);
}
$stmt = null;
// get data row by row using bound ouput columns
$stmt = $dbh->prepare('select name, value from test');
$stmt->execute();
$stmt->bindColumn('name', $name);
$stmt->bindColumn('value', $value)
while ($stmt->fetch(PDO_FETCH_BOUND)) {
echo "name=$name, value=$value\\n";
}
Если вы счастливый обладатель нетбука Samsung и решили установить Ubuntu Netbook Remix (в моем случае это Samsung n150 с предустановленной Windows 7) и если у вас что-то вдруг не работает из коробки, например, подсветка экрана при работе от аккумулятора и fn-keys регулирования уровня подсветки, как у меня, то вам необходимо установить полезные пакеты из следующего репозитория
Версия ZF: 1.10. Создание собственного элемента формы Zend_Form довольно тривиально. Ниже пример для класса Securimage. Собственно в Zend Framework достаточно вариантов капчи на любой вкус, все это лишь для иллюстрации того, как это работает. Где-то у нас есть объект Zend_View ... Надо указать путь к хелперам (view helpers). Допустим они у нас в каталоге Custom (по умолчанию Zend_View смотрит Zend/View/Helper/).
$view = new Zend_View(); $view->setHelperPath('Custom/View/Helper/', 'Custom_View_Helper_');
Объект вида можно хранить, допустим в реестре, а вообще как хотим.
файл: Custom/Form/Element/Securimage.php
class Custom_Form_Element_Securimage extends Zend_Form_Element { public $helper = 'Securimage'; }
Собственно и все, просто указали хелпер вида для отображения, в данном случае. Все может быть гораздо сложнее, но нам тут это не нужно.
Одноименный метод хелпера возвращает html-код нашего элемента. Это то что мы увидим в результате вызова метода render нашего элемента.
Ну и наконец нам нужен валидатор значения нашего элемента. Подключение класса Securimage обеспечено автозагрузчиком. Валидатор наследует класс фреймворка Zend_Validate_Abstract и должен реализовать метод isValid с определенным списком параметров (это важно, иначе он не будет вызван методом isValid класса Zend_Form).
файл: Custom/Validate/Securimage.php
class Custom_Validate_Securimage extends Zend_Validate_Abstract { const INVALID = 'invalid';
public function isValid($val, $context = null) { $val = (string) $val; $this->_setValue($val); $si = new Securimage(); if(!$si->check($val)) { $this->_error(self::INVALID); return false; } return true; } }
Осталось совсем немного, создать форму и добавить туда наш элемент, примерно так ...
class MyForm extends Zend_Form { pulic function init() { // ....
$si = new Custom_Form_Element_Securimage('cap'); $si->addValidator(new Custom_Validate_Securimage()); $si->setRequired(); $si->setLabel('Код'); $this->addElement($si);
// .... } }
Пути к файлам элемента и валидатора указывать не требуется, все включается автоматически. Если нет, то возможно потребуется явно подключить все необходимые файлы.
Perl в пакете XAMPP для Linux к сожалению собран без поддержки threads. Можно пользоваться perl из системы. Для работы с MySQL через DBI при подключении указываем сокет MySQL из XAMPP.
my $dbh = DBI->connect("DBI:mysql:database=$db_name;mysql_socket=/opt/lampp/var/mysql/mysql.sock", $db_user, $db_pwd);