Блог веб-программиста

21Фев/132

NetPlant — простая хостинговая панель

В силу необходимости, решил написать свою хостинговую панель для shared хостинга.

Почему свою? Всё просто.

Ни одна из тех панелей, что я нашел, не умеет:

  • Работать с несколькими серверами из одной панели
  • Давать возможность создавать сайты со своими конфигами
  • Работать в конфигурации nginx+php-fpm, nginx+apache одновременно

Результат моего 2.5 дневного творения уже можно пощупать на github: https://github.com/DevGroup-ru/NetPlant.
Пока что умеет только создавать сайты на серверах из конфигов, но лично мне это уже хорошо упрощает жизнь.

Основано на:

  • Yii framework 1.x
  • Предыдущих наработках для движка CMS
  • Интерфейс - twitter bootstrap (via YiiBooster)

По поводу лицензии пока не задумывался - сначала надо довести до более-менее стабильной версии.

Связано с категорией: NetPlant 2 Комментарии
9Авг/120

Необычное проявление ошибки failed to open stream: No such file or directory

В Yii Framework, как и во многих других фреймворках, принято подгружать классы стандартной для PHP автозагрузкой.

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

PHP Error [2]
include(EasmSelectEx.php): failed to open stream: No such file or directory (/Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/YiiBase.php:423)
#0 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/YiiBase.php(423): DotPlantWebApplication->handleError()
#1 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/YiiBase.php(423): autoload()
#2 unknown(0): autoload()
#3 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/web/CWidgetFactory.php(148): spl_autoload_call()
#4 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/web/CBaseController.php(147): CWidgetFactory->createWidget()
#5 /Users/bethrezen/Documents/DotPlant-private/yii-framework/framework/web/CBaseController.php(173): AsmSelect->createWidget()
#6 /Users/bethrezen/Documents/DotPlant-private/protected/modules/User/widgets/AsmSelect.php(75): AsmSelect->widget()

Казалось бы проблема в отсутствующем файле, но это не так. Файл присутствует и права на месте.

Проблема же была в том, что в этом файле использовались short tags - <? вместо <?php.

В общем, странно, непредсказуемо, но логично. Ещё раз доказывает, что короткие теги не нужны.

Связано с категорией: Code Нет комментариев
28Апр/120

Yii: CStatRelation и defaultScope у реляций

Ночью столкнулся с внезапной проблемой в Yii Framework 1.
Оказывается, статистические запросы через CStatRelation не поддерживает scopes в параметрах. Так что, если мы имеем defaultScope в нашем связанно элементе, то отменить его действие мы не сможем.

Как повторить эту проблему. Допустим имеем класс RevisionsSets с таким вот определением реляций:

        /**
	 * @return array relational rules.
	 */
	public function relations()
	{
		return array(
			'pricesCount'=>array(
					self::STAT, 'Revisions', 'revisionSetId',
				),
		);
	}

Ну и в самом классе Revisions имеем следующую группу условий по-умолчанию:

        public function defaultScope() {
		$rev = Config::model()->getConfigValue("Shop", "CurrentRevision")->value;
		$t = $this->getTableAlias(false, false);
 
		return array(
					'condition' => "$t.revisionSetId=:rev",
					'params' => array('rev'=>$rev),
				);
 
	}

Что же происходит при вызове $revisionsSetModel->pricesCount?
STAT-реляция забирает количество записей, но при этом применяет defaultScope от модели Revisions и в итоге для всех экземпляров RevisionsSets считается некорректное количество записей.
Исправить такое поведение можно было бы допливанием CStatRelation и реализацией там поддержки условий, как это например сделано в HAS_MANY, MANY_MANY, BELONGS_TO.

Но мне в голову пришел более быстрый вариант. Я создал класс RevisionsResetScope, который наследует Revisions и переопределяет defaultScope:

<?php
 
class RevisionsResetScope extends Revisions {
	public function defaultScope() {
		return $this->resetScope();
	}
}

Этот класс и используем в реляции:

        /**
	 * @return array relational rules.
	 */
	public function relations()
	{
		return array(
			'pricesCount'=>array(
					self::STAT, 'RevisionsResetScope', 'revisionSetId',
				),
		);
	}

Вот такой костыль. Кстати, на форуме Qiang Xue решил отказаться от статистических запросов и CStatRelation в Yii Framework 2. Будем надеяться, что разработчики предусмотрят достойную замену.

Связано с категорией: Code Нет комментариев
16Сен/093

Создаём расширяемую структуру на Yii Framework

Хочу предложить Вашему вниманию концепт расширяемой структуры приложения на Yii Framework. Я уже писал как сделать свои Actions на Yii.

Сегодня же речь пойдёт о написании стандартных экшенов для контроллеров и их расширения.

Предположим, в приложении у нас все контроллеры наследуются от класса dotPlantFrontMainController.

Нам необходимо, чтобы у всех контроллеров было действие Breadcrumb.

Для этого, в базовом контроллере dotPlantFrontMainController переопределяем функцию actions() следующим образом:

public function actions()
 {
 return array(
 'breadcrumb' => 'application.extensions.actionBreadcrumb',
 );
 }

Если в унаследованном контроллере(скажем News) мы используем экшены из других файлов, то нам необходимо также переопределить функцию примерно вот так:

public function actions()
 {
 // return external action classes, e.g.:
 return array_merge(
 parent::actions(),
 array(
 'admin'=>'application.controllers.News.ActionAdmin',
 )
 );
 }

Таким образом, в News будут экшены определенные в базовом классе dotPlantFrontMainController плюс ActionAdmin.

Переписать же actionBreadcrumb можно уже в теле самого News.

В итоге имеем легко расширяемую структуру. В самом же базовом классе массив actions можно автоматически генерировать в соответствии с установленными расширениями. Всё легко и просто 🙂

Связано с категорией: Code 3 Комментарии
29Май/090

Yii — создание своих типов Action-ов

Пишу одно прлиожение на Yii Framework. Структура приложения такова, что необходимо разграничить экшены контроллеров(CController) по папкам и сделать их типовыми.
Экшены разграничиваются легко.
Предположим, что у нас есть ряд экшенов для администрирования. Всем им надо установить какие-либо свойства или же сделать при их вызове какие-то типовые действия.
Рассмотрим на примере изменения титла страницы.
Вот код моего базового экшена:

class dotPlantAdminAction extends CAction
 {
 /**
 * Constructor.
 * Runs CAction constructor and makes some changes for Admin action type
 */
 public function  __construct($controller,$id)
 {
 parent::__construct($controller,$id);
 $this->controller->pageTitle       = dotPlant::getName() . " - Admin ";
 
}
 
public function run()
 {
 
 }
 }

В конструкторе мы сначала вызываем parent::__construct с необходимыми параметрами. Это грубо-говоря идёт инициализация базового CAction.

Допустим у нас есть контроллер SettingsController. И нам нужно сделать его на основе нашего экшена. Создаем папку  protected/controllers/Settings/. В ней создаем файл ActionAdmin.php с таким вот кодом:

class ActionAdmin extends dotPlantAdminAction
{
 public function run()
 {
    $this->controller->render('admin');    
 }
}

Видите? Нам достаточно только объявить run() и уже всё готово. При загрузке запустится необходимый нам конструктор базового контроллера с нашими действиями.

Вот по такому принципу я разграничиваю например админку в своей CMS dotPlant на Yii Framework. Слава PHP пятому!

Связано с категорией: Code Нет комментариев