Bootstrap PHP


PHP библиотека для создания компонентов Twitter Bootstrap проще и быстрее.

Скачать   Требования PHP 5.3 и Bootstrap 2.3

Посмотреть на GitHub

История появления библиотеки

Работая над админкой своего проекта (админка делается на Bootstrap) обнаружил, что мне очень не хватает возможности прямо из php формировать содержание элементов Bootstap.

Например:

  1. Наполнять содержания выпадающих списков меню в зависимости от прав пользователя
  2. Наполнять навигационный бар элементами в зависимости от многих факторов, он у меня используется для профайлера
  3. Количество и разнообразие кнопок очень велико, поэтому для них хотелось бы иметь также простой способ создания

... и множество других вещей, также хотелось формировать прямо в php коде.

Кроме того на сайте уже были использованы хлебные крошки, навигация, pager и некоторые другие компоненты Bootstrap.

Чтобы иметь только один файл шаблон для каждого компонента, а не множество на каждый случай использования, я создавал классы конструкторы, которые позволяли наполнить и кастомизировать каждый компонент. Когда их стало значительно количество, решил выделить их в отдельный проект, а потом пришел к мысли, что это может быть полезно не только мне.

Зачем?

Так зачем библиотека вам? Прочитайте историю появления выше, и если у вас похожая ситуация, то рано или поздно вы придете к тому что вам потребуется что-то подобное.

Чем Bootstrap.PHP лучше "чистого" Bootstrap?

  1. Создать выпадающее меню или навигационную панель проще на Bootstrap.PHP, чем на "чистом" Bootstrap. И не только их, чем сложнее компонент, тем более явно это преимущество.
  2. Каждый программист знает, что нужно избегать повторения кода. Также хочется избегать повторения html в шаблонах. Когда на основе одно и того же компонента Bootstrap создается несколько разных шаблонов, повторение неизбежно. Bootstrap.PHP помогает этого избежать.
  3. Bootstrap.PHP позволяет создавать шаблоны быстрее (да его можно использовать прямо в шаблонах, конечно если у вас шаблоны на php). Просто поверьте моему опыту. Я практически перестал заглядывать в документацию Bootstrap, а это экономит кучу времени, и это не потому что я знаю ее наизусть. В документацию Bootstrap.PHP также заглядывать не нужно, почему, будет понятно ниже.

Авто дополнение и PHPDocs

Что делает эту библиотеку такой замечательной так это автодополнение. Используя автодополнение и подсказки phpdocs, вам не придется обращаться к этой документации.

Смотрите сами:

  1. Взглянув на названия параметров легко понять их предназначение, phpdocs помогут, если что-то непонятно



  2. Увидев названия методов вспоминаешь какие возможности есть у компонента, опять же phpdocs



  3. Никаких "магических" строк, если параметр имеет ограниченное количество значений, то его можно задать с помощью соответствующей константы этого же класса



  4. Вот как просто добавляется выпадающее меню к кнопке



Установка

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

<?php
use BootstrapPHP\BootstrapPHP;

include 'BootstrapPHP/BootstrapPHP.php';
BootstrapPHP::register_autoload();
?>

Все, библиотека готова к работе.

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

Любой компонент можно создать двумя способами. Посмотрим на примере компонента Button.

<?php
use BootstrapPHP\Button;

// Превый способ (не рекомундуется)
$button = new Button('Текст на кнопке');

// Второй способ (рекомендованный)
Button::create('Текст на кнопке');
?>

Полное имя класса кнопки \BootstrapPHP\Button для более короткой записи используется use BootstrapPHP\Button. В дальнейших примерах блок с use может быть пропущен.

Почему рекомендован второй способ?

  1. Во-первых, он позволяет сделать следующее

    <?php
    Button::create('Текст на кнопке')->setTag(Button::TAG_BUTTON);
    
    // Вместо
    $button = new Button('Текст на кнопке');
    $button->setTag(Button::TAG_BUTTON);
    ?>
  2. Во-вторых, автодополнения будет содержать только те свойства и методы которые вам необходимы, а те методы, которые нужны не для создания компонента, а для получения данных о нем, то есть те, что используются самой библиотекой, в авто дополнении будут отсутствовать. Чем меньше список доступных методов, тем удобнее с ними работать. Как это сделано, можно легко понять, заглянув в код библиотеки.

Гибкость компонентов

Bootstrap.PHP включает в себя не все компоненты, которые есть в Bootstrap. Для включения в библиотеку были выбраны только те, которые скорее всего будут использовать как есть, то есть с внесением в их код минимальных изменений. Вряд ли вы будете что-то сильно менять в кнопках Bootstrap’а или в панели навигации, их функционала достаточно. Чего не скажешь, например, о таблицах или формах, конструкторы которых, могли бы быть отдельными большими проектами.

HTML атрибуты

Но все же, минимальная гибкость нужна, например, для задания идентификатора, добавления классов или data атрибутов. Для этого у каждого объекта компонента есть свойство attributes.

<?=
Button::create('Кнопка с заданными атрибутами')
	->attributes->setId('myButton')
	->attributes->addClass('class_1')
	->attributes->addClass(array('class_2', 'class_n'))
	->attributes->addData('name-1', 'value 1')
	->attributes->addData(array('name-2' => 'value 2', 'name-n' => 'value n'));
?>

Результат:

<a
	id="myButton"
	class="btn class_1 class_2 class_n"
	data-name-1="value 1" data-name-2="value 2" data-name-n="value n"
>
	Кнопка с заданными атрибутами
</a>

Если вы используете цепочку вызовов как показано в примере, то использовать свойство attributes лучше не в одной цепочке с методом create, так как это сломает авто дополнение, при дальнейшем использовании. Используйте прием как показано ниже.

<?php
// Так будет сломано авто дополнение
$button = Button::create('Кнопка')
	->setType(Button::TYPE_PRIMARY)
	->attributes->addClass('class');

// Вот так правильно
$button = Button::create('Кнопка')
	->setType(Button::TYPE_PRIMARY);
$button
	->attributes->addClass('class');
?>

И тот и другой работают одинаково, но второй способ позволит пользовать авто дополнением для $button в дальнейшем.

У сложных объектов у которых есть методы добавляющие в них элементы, атрибуты можно добавлять элементам.

<?=
DropdownMenu::create()
	->addLink(
		'Пункт выпадающего меню', '/link/', false, false, false,
		Attributes::create()->setId('myDropdownMenuLink')->addClass('class')
	)
?>

Результат:

<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
	<li>
		<a id="myDropdownMenuLink" tabindex="-1" href="/link/" class="class">
			<i class="i"></i> Пункт выпадающего меню
		</a>
	</li>
</ul>

Практика показала, что атрибуты нужно добавлять именно ссылке, а не элементу списка, так как Bootstap’ом data атрибуты проверяются у ссылок.

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

Нигде в проекте, где можно задать произвольный текст, не используется обработка введенного текста, текст вставляется как есть. Это значит, что везде можно использовать html и он будет вставлен как html. Это сделано для большей гибкости, так как моя собственная практика показала, что в реальном проекте без этого не обойтись. Хотя бы для того, чтобы добавить иконку рядом с текстом, в тех местах, где в проекте специально это не предусмотрено.

Метка с иконкой
<?=
Label::create(Icon::create(I::TYPE_HAND_LEFT, true).' Метка с иконкой');
// или так если считаете что для создание иконки использовать php это перебор
Label::create('<i class="icon-hand-left icon-white"></i> Метка с иконкой');
?>

Получение готового HTML

Получить готовый html код объекта можно двумя способами. Выбирайте тот, что больше нравится.

<?php
// Первый способ (приведение объекта к строке приводит к вызову метода __toString())
echo Button::create('Текст на кнопке');

// Если хочется посмотреть получившийся html
var_dump((string) Button::create('Текст на кнопке'));

// Второй способ (вызов специального метода toHtml())
echo Button::create('Текст на кнопке')->toHtml();
?>
<?=
Button::create('Обычная кнопка', '/link/')
?>

<?=
Button::create('Заблокированная кнопка занимающая всю доступную ширину', '/link/', Icon::TYPE_DOWNLOAD)
	->setType(Button::TYPE_PRIMARY)
	->setWidth(Button::WIDTH_BLOCK)
	->setEnable(false);
?>

<?=
Button::create('Маленькая кнопка переключатель')
	->setSize(Button::SIZE_SMALL)
	->makeToggle()
?>

<?php
echo Button::create('Тег по умолчанию')->setTag(Button::TAG_DEFAULT);
echo Button::create(htmlspecialchars('<a>'))->setTag(Button::TAG_A);
echo Button::create(htmlspecialchars('<button>'))->setTag(Button::TAG_BUTTON);
echo Button::create(htmlspecialchars('<input>'))->setTag(Button::TAG_INPUT);
?>

<?=
Button::create('Нажми на меня')
	->setLoadingText('Loading ...')
	->attributes->setId('myLoadingButton');
?>
<script type="text/javascript">
$('#myLoadingButton').click(function(){
	$(this).button('loading');
	return false;
});
</script>

Иконку можно создать использую класс Icon или I которые являются синонимами.

<?= I::create(I::TYPE_USER); ?>

В большинстве случаев вам не придётся иметь дело с созданием иконки с помощью объекта, так как у тех компонентов, которые часто исползают совместно с иконками есть параметр функции для ее добавления. В нем вы можете использовать как просто константу иконки так и объект иконки. Объект иконки необходим если вы принудительно хотите сделать иконку белой или черной.

<?php
echo Button::create('Кнопка с иконкой', false, I::TYPE_USER)
	->setType(Button::TYPE_SUCCESS);
echo '<br>';
// или так
echo Button::create('Кнопка с иконкой', false, I::create(I::TYPE_USER , false)) // делаем черной
	->setType(Button::TYPE_SUCCESS);
?>

ButtonGroup

<?=
ButtonGroup::create()
	->addButton(Button::create('', '#left', Icon::TYPE_ALIGN_LEFT))
	->addButton(Button::create('', '#center', Icon::TYPE_ALIGN_CENTER))
	->addButton(Button::create('', '#right', Icon::TYPE_ALIGN_RIGHT));
?>

<?php
echo ButtonGroup::create()
	->addButton(Button::create('CHECKBOX'))
	->addButton(Button::create('CHECKBOX'))
	->makeToggle(ButtonGroup::TYPE_TOGGLE_CHECKBOX);

echo ButtonGroup::create()
	->addButton(Button::create('RADIO'))
	->addButton(Button::create('RADIO'))
	->makeToggle(ButtonGroup::TYPE_TOGGLE_RADIO);
?>

<?=
ButtonGroup::create()
	->addButton(Button::create('', '#', Icon::TYPE_ARROW_RIGHT))
	->addButton(Button::create('', '#', Icon::TYPE_ARROW_DOWN))
	->setAlign(ButtonGroup::ALIGN_RIGHT)
	->setDirection(ButtonGroup::DIRECTION_VERTICAL)
?>

ButtonToolbar

<?=
ButtonToolbar::create()
	->addButtonGroup
	(
		ButtonGroup::create()
			->addButton(Button::create('<b>Ж</b>'))
			->addButton(Button::create('<i>К</i>'))
	)
	->addButtonGroup
	(
		ButtonGroup::create()
			->addButton(Button::create('', '#left', Icon::TYPE_ALIGN_LEFT))
			->addButton(Button::create('', '#right', Icon::TYPE_ALIGN_RIGHT))
	);
?>
<?=
Button::create('Кнопка с меню')
	->addDropdownMenu(
		DropdownMenu::create()
			->addLink('Ссылка 1')
			->addDivider()
			->addLink('Ссылка 2')
			->end()
	)
?>

<?php
$dm = DropdownMenu::create()
	->addLink('Ссылка 1')
	->addDivider()
	->addLink('Ссылка 2')
	->end();

echo Button::create('С отдельной кнопкой')
	->addDropdownMenu($dm, true);

echo Button::create('С выравниванием списка справа')
	->addDropdownMenu($dm, true, true);

echo Button::create('С выпадением вверх')
	->addDropdownMenu($dm, true, true, true);
?>
<?php
/** @var Tabs $nav */
foreach(array(new Tabs(), new Pills()) as $nav)
{
	echo $nav
		->addItem('Ссылка 1 (активная)', '/1/', false, true)
		->addItem('Ссылка 2', '/2/')
		->addItem('Ссылка 3 (заблокирована)', '/3/', true)
		->startDropdown('Выпадающее меню')
			->addItem('Ссылка 4', '/4/')
			->addDivider()
			->addItem('Ссылка 5 (заблокировна)', '/5/', true)
		->endDropdown()
		->addItem('И еще одна ссылка', '/6/');
	echo '<br>';
}
?>

<?=
Pills::create()
	->addItem('Ссылка 1 (активная)', '#', false, true)
	->addItem('Ссылка 2', '#')
	->addItem('Ссылка 3 (заблокировна)', '#', true)
	->makeStacked();
?>

Содержание раздела 1

Содержание раздела 2

Содержание раздела 3

<?=
Tabs::create()
	->addContentItem('Раздел 1', 'section_1', 'Содержание раздела 1', false, true)
	->addContentItem('Раздел 2', 'section_2', 'Содержание раздела 2')
	->addContentItem('Раздел 3', 'section_3', 'Содержание раздела 3', true)
	->makeFaded();
?>

Содержание раздела А

Содержание раздела Б

<?=
Tabs::create()
	->setDirection(Tabs::DIRECTION_LEFT)
	->addContentItem('Раздел А', 'section_a', 'Содержание раздела А', false, true)
	->addContentItem('Раздел Б', 'section_b', 'Содержание раздела Б');
?>

В выше приведенном примере важен порядок для корректной работы авто дополнения.

<?=
Pagination::create()
	->addItem(htmlspecialchars('<<'), '/first/', false, true) // передавать нужно иметь html
	->addItem(htmlspecialchars('<'), '/back/', false, true)   // об этом написано выше
	->addItem('1', '/1/', true)
	->addItem('2', '/2/')
	->addItem('3', '/3/')
	->addItem(htmlspecialchars('>'), '/next/')
	->addItem(htmlspecialchars('>>'), '/last/')
	->setSize(Pagination::SIZE_LARGE) // делаем большой
	->setAlign(Pagination::ALIGN_CENTER); // выравниваем по центру
?>
<?=
Pager::create()
	->addItem('1', '/1/')
	->addItem('2 <i>(заблокированный)</i>', '/2/', true)
	->addItemPrevious('Предыдущий', '/back/')
	->addItemNext('Следующий', '/next/', true);
?>

Задать пользовательские стрелки можно следующих образом

<?php
echo Pager::create()
	->addItemPrevious('Предыдущий', '/back/')
	->addItemNext('Следующий', '/next/')
	->setArrowLeft(htmlentities('<<'))
	->setArrowRight(htmlentities('>>'));

echo Pager::create()
	->addItemPrevious('Предыдущий', '/back/')
	->addItemNext('Следующий', '/next/')
	->setArrowLeft(I::create(I::TYPE_HAND_LEFT))
	->setArrowRight(I::create(I::TYPE_HAND_RIGHT));
?>
  • TYPE_DEFAULT
  • TYPE_INVERSE
  • TYPE_IMPORTANT
  • TYPE_INFO
  • TYPE_SUCCESS
  • TYPE_WARNING
<ul>
	<li><?= Label::create('TYPE_DEFAULT'); ?></li>
	<li><?= Label::create('TYPE_INVERSE', 	Label::TYPE_INVERSE); ?></li>
	<li><?= Label::create('TYPE_IMPORTANT', Label::TYPE_IMPORTANT); ?></li>
	<li><?= Label::create('TYPE_INFO', 	Label::TYPE_INFO); ?></li>
	<li><?= Label::create('TYPE_SUCCESS', 	Label::TYPE_SUCCESS); ?></li>
	<li><?= Label::create('TYPE_WARNING', 	Label::TYPE_WARNING); ?></li>
</ul>

  • 1
  • 2
<ul>
	<li><?= Badge::create(1); ?></li>
	<li><?= Badge::create(2, Label::TYPE_SUCCESS); ?></li>
</ul>
× TYPE_DEFAULT Cообщение для пользователя.
× TYPE_SUCCESS Cообщение для пользователя.
× TYPE_INFO Cообщение для пользователя.
× TYPE_ERROR Cообщение для пользователя.
<?php
echo Alert::create('<b>TYPE_DEFAULT</b> Cообщение для пользователя.');
echo Alert::create('<b>TYPE_SUCCESS</b> Cообщение для пользователя.', Alert::TYPE_SUCCESS);
echo Alert::create('<b>TYPE_INFO</b> Cообщение для пользователя.', Alert::TYPE_INFO);
echo Alert::create('<b>TYPE_ERROR</b> Cообщение для пользователя.', Alert::TYPE_ERROR);
?>

×

TYPE_SUCCESS

Cообщение для пользователя.
<?=
// Для крупных сообщений используется 3ий параметр
Alert::create('<h4>TYPE_SUCCESS</h4> Cообщение для пользователя.', Alert::TYPE_SUCCESS, true);
?>
20% TYPE_INFO

30% TYPE_SUCCESS

40% TYPE_DANGER

10%
20%
30%
<?php
echo Progress::create(20, Progress::TYPE_INFO, '20% TYPE_INFO');
echo '<br>';
echo Progress::create(30, Progress::TYPE_SUCCESS, '30% TYPE_SUCCESS')
	->makeStriped();
echo '<br>';
echo Progress::create(40, Progress::TYPE_DANGER, '40% TYPE_DANGER')
	->makeStriped(true);
echo '<br>';
echo ProgressStack::create()
	->addBar(10, ProgressStack::TYPE_INFO, '10%')
	->addBar(20, ProgressStack::TYPE_SUCCESS, '20%')
	->addBar(30, ProgressStack::TYPE_DANGER, '30%');
?>

Для желающих убедиться в работоспособности библиотеки выкладываю тесты. Они покрывают полный функционал всех компонентов. В этом можно быстро убедиться - посмотреть тесты online, либо скачать исходный код.

Кстати эта страница с документацией сделана с помощью Bootstrap.PHP, что частично подтверждает ее работоспособность.




comments powered by Disqus