Новости Joomla

SW JProjects v.2.6.1 - компонент каталога расширений для веб-приложений

👩‍💻 SW JProjects v.2.6.1 - компонент каталога расширений для веб-приложений.

Компонент позволяет сделать свой мини-Joomla Extensions Directory - каталог расширений для CMS (не только для Joomla) или файлов. Есть возможность скачивания по лицензионным ключам создания кастомных схем данных для сервера обновлений.

v.2.6.1. Что нового?

  • Правки наследования схем серверов обновлений. Улучшена логика наследования схем серверов обновлений для проектов компонент - категория - проект.
  • Не стабильные релизы в сервере обновлений. Теперь в данные сервера обновлений попадают все версии (alpha, beta и т.д.), а не только stable.
  • Косметические изменения. В шаблоне по умолчанию сделаны замены некоторых CSS-классов, уточнено присвоение атрибутов loading=lazy и fetchpriority.
  • Рефакторинг и правки кода. Текущее обновление кодовой базы.
  • Исправление ошибок.

Больше спасибо за помощь в тестировании участникам нашего сообщества Александру Новикову (@pro_portal) и Александру Судьбинову (@alexrevo).

Событие Pizza, Bugs & Fun - 29-30 января 2026 года.

Событие Pizza, Bugs & Fun  - 29-30  января 2026 года.

Уже несколько лет в мире Joomla проводятся мероприятия "Pizza, Bugs & Fun" (#PBF), где каждый может посвятить несколько часов своего мозгового времени тому, чтобы наша любимая CMS стала ближе к идеалу.

Ссылки на видео и статьи из этого поста рассказывает об организационных вопросах, которые пригодятся для участия в PBF, а так же что и как делать.

В рамках события PBF все желающие могут собираться в общий онлайн чат, обсудить вопросы Joomla и приложить к их разрешению свою руку. Самый классный вариант, когда эта встреча происходит оффлайн: тогда организовывается пицца, напитки по вкусу и несколько часов совместного творчества.

Каждый помогает тем, что он умеет:

  • кто-то пишет недостающую документацию,
  • кто-то пишет код,
  • кто-то тестирует как исправлены ошибки или сделан новый функционал.

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

https://www.youtube.com/watch?v=a-FuVKXg_Uw 

На момент написания данного поста в репозитории Joomla 810 открытых Issue (как правило это баги) и 236 Pull request (PR, исправление багов и новый функционал). Все PR обязательно тестируются минимум двумя участниками сообщества, дабы в конечный код движка не проскочила ошибка.

Если каждый из участников только нашего сообщества сделает даже одно тестирование, то, боюсь, PR и Issue на всех не хватит 😀 И ничего не останется нашим коллегам из международных Joomla-чатов.

0 Пользователей и 1 Гость просматривают эту тему.
  • 18 Ответов
  • 1860 Просмотров
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Всем добрый день!

Пытаюсь сделать свой собственный компонент для Joomla и никак не могу понять как произвести вставку данных в базу.

У меня есть вид в административной панели, который выводит несколько полей и кнопку (вставить). - с этим всё ясно.
Есть javascript код, который при клике на кнопку делает итерацию всех нужных полей вида, сериализует их и отправляет через AJAX в контроллер. - с этим тоже всё ясно.

Контроллер в свою очередь должен отправить это в модель и получить ответ, что вставка данных прошла успешно.

Я не понимаю 2 вещи:

1) Как сделать вставку данных в базу?
2) Каким образом работает модель? Как к ней обратится?

Чтобы не быть голословным, я приведу более подробный пример.

У меня есть пример компонента com_lendr (Сервис по прокату книг). Я решил разобрать этот пример, так как в Joomla я новичок.

Вот например javascript функция - добавить книгу.

Код
function addBook()
{
var bookInfo = {};
jQuery("#bookForm :input").each(function(idx,ele){
bookInfo[jQuery(ele).attr('name')] = jQuery(ele).val();
});

jQuery.ajax({
url:'index.php?option=com_lendr&controller=add&format=raw&tmpl=component',
type:'POST',
data:bookInfo,
dataType:'JSON',
success:function(data)
{
if ( data.success ){
jQuery("#book-list").append(data.html);
jQuery("#newBookModal").modal('hide');
}else{

}
}
});

}

тут всё ясно. вопросов нет.

Далее контроллер: add.php

Код
class LendrControllersAdd extends JControllerBase
{
  public function execute()
  {
    $app      = JFactory::getApplication();
    $return   = array("success"=>false);

    $modelName  = $app->input->get('model', 'Book');
    $view       = $app->input->get('view', 'Book');
    $layout     = $app->input->get('layout', '_entry');
    $item       = $app->input->get('item', 'book');

    $modelName  = 'LendrModels'.ucwords($modelName);

   $model = new $modelName();
   if ( $row = $model->store() )
   {
   $return['success'] = true;
   $return['msg'] = JText::_('COM_LENDR_SAVE_SUCCESS');

     $return['html'] = LendrHelpersView::getHtml($view, $layout, $item, $row);
   }else{
   $return['msg'] = JText::_('COM_LENDR_SAVE_FAILURE');
   }
    
   echo json_encode($return);

  }

}


Тут я не совсем разобрался, но более-менее понятно, что он обращается к модели (вернее к одной из её функций)

Код
public function store($data=null)
  {   
    $data = $data ? $data : JRequest::get('post');
    $row = JTable::getInstance($data['table'],'Table');

    $date = date("Y-m-d H:i:s");

     // Bind the form fields to the table
    if (!$row->bind($data))
    {
        return false;
    }

    $row->modified = $date;
    if ( !$row->created )
    {
      $row->created = $date;
    }

    // Make sure the record is valid
    if (!$row->check())
    {
        return false;
    }
 
    if (!$row->store())
    {
        return false;
    }

    return $row;

  }

Я не понимаю как работает модель, каким образом данные вставляются в базу.
Буду рад любой помощи, спасибо!
*

robert

  • Живу я здесь
  • 4974
  • 457 / 20
1) Как сделать вставку данных в базу?
Данные ($data) задаются как аргумент, в противном случае берутся из $_POST.
Затем вызывается экземпляр объекта JTable ($row), который загружает нужную таблицу ($data['table']).
$row сначала натягивает данные на структуру таблицы (bind()), затем проверяет валидность данных (check()) и если все нормально - записывает их (store()).
Подробности смотрите в классе JTable.
2) Каким образом работает модель? Как к ней обратится?
Код: php-brief
$modelName  = 'LendrModels'.ucwords($modelName);
$model = new $modelName();
Не будь паразитом, сделай что-нибудь самостоятельно!
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Спасибо, стало яснее, но вот этот вот момент не понятен -

Цитировать
Данные ($data) задаются как аргумент, в противном случае берутся из $_POST.
Затем вызывается экземпляр объекта JTable ($row), который загружает нужную таблицу ($data['table']).

Вернее - где тут именно имя таблицы?

По идее должно идти обращение к таблице - #__lendr_books
Но оно нигде не упоминается.
*

robert

  • Живу я здесь
  • 4974
  • 457 / 20
Вернее - где тут именно имя таблицы?
$data['table']. Скорее всего, в форме, откуда вы отправляете данные, есть скрытое поле с таким значением.
[offtop]
ТС, я сам - самоучка, и на этом форуме я задал только 1 вопрос, на который так и не получил ответа. На самом деле, все намного лучше осваивается, когда вы сами учитесь, не полагаясь на чужую помощь.
[/offtop]
Не будь паразитом, сделай что-нибудь самостоятельно!
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Спасибо за помощь! На самом деле всё было гораздо хуже, а теперь намного понятнее.
Да мне нужно было всего то пара разъяснений.
*

zomby6888

  • Завсегдатай
  • 1473
  • 171 / 3
robert, позвольте вас поправить, ну а вы конечно можете со мной поспорить, увы не мог пройти мимо и не отметить:

Цитировать
Затем вызывается экземпляр объекта JTable ($row), который загружает нужную таблицу ($data['table']).

Не объекта а класса. У объекта не может быть экземпляра, если он не является классом, а в php объекты не являются классами. К сожалению, а может быть и к радости. Ну тут я может конечно придираюсь к формулировке но:

Цитировать
$modelName  = 'LendrModels'.ucwords($modelName);
$model = new $modelName();

С Joomla же вроде работаем. Из любого места компонента можно обратится к модели:

Код: php
JModelLegacy::getInstance($modelName, 'LendrModels');
 

А из одноименного контроллера так вообще:

Код: php
$this->getModel( $modelName );

Цитировать
ТС, я сам - самоучка, и на этом форуме я задал только 1 вопрос, на который так и не получил ответа. На самом деле, все намного лучше осваивается, когда вы сами учитесь, не полагаясь на чужую помощь.

Ну и тут конечно тоже не согласен, считаю что нужно задавать вопросы чаще, хоть и сам грешен, гуглом избалован донельзя. Нет таких людей которые знают ответы на все свои вопросы, зато дофига таких, которые боятся или стесняются их задавать. Вопросы тем более не из разряда "Как мне сделать кнопочку чтобы все было ништяк".
интернет-блог: http://websiteprog.ru
*

robert

  • Живу я здесь
  • 4974
  • 457 / 20
Не объекта а класса.
OK.
Ну тут я может конечно придираюсь к формулировке но:
С Joomla же вроде работаем.
ТС задал вопрос на конкретном примере.
Ну и тут конечно тоже не согласен, считаю что нужно задавать вопросы чаще
Здесь я останусь при своем: за время ожидания ответов можно самостоятельно решить не только один вопрос.
Не будь паразитом, сделай что-нибудь самостоятельно!
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Всем добрый день! Вынужден поднять данную тему ещё раз( К сожалению мне не обойтись без вашей помощи.

Суть в чём - я просто пытаюсь понять последовательность происходящих действий. В Joomla (а вернее в моём примере) всё как то сильно разбросано по файлам и не понятно откуда что вызывается.


Вот смотрите, как я писал ранее, вначале через AJAX инициируем вызов контроллера

Код
jQuery.ajax({
        url:'index.php?option=com_lendr&controller=add&format=raw&tmpl=component',
        type:'POST',
        data:itemInfo,
        dataType:'JSON',

Кстати не понятно - Joomla достаточно указать имя файла контроллера? Потому что насколько мне известно по всем канонам, вначале указывается имя файла, а потом имя самой функции, которую нужно вызвать через AJAX.
Ну не суть.

Далее идёт файл контроллера controllers/add.php

Код
class LendrControllersAdd extends JControllerBase
{
  public function execute()
  {
    $app      = JFactory::getApplication();
    $return   = array("success"=>false);

    $modelName  = $app->input->get('model', 'Book');
    $view       = $app->input->get('view', 'Book');
    $layout     = $app->input->get('layout', '_entry');
    $item       = $app->input->get('item', 'book');

    $modelName  = 'LendrModels'.ucwords($modelName);

  $model = new $modelName();
    if ( $row = $model->store() )
  {
  $return['success'] = true;
  $return['msg'] = JText::_('COM_LENDR_SAVE_SUCCESS');

     $return['html'] = LendrHelpersView::getHtml($view, $layout, $item, $row);
  }else{
  $return['msg'] = JText::_('COM_LENDR_SAVE_FAILURE');
  }
   
  echo json_encode($return);

  }

}

Как подсказал ранее robert:
Цитировать
$data['table']. Скорее всего, в форме, откуда вы отправляете данные, есть скрытое поле с таким значением.

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

Но вот что происходит дальше(в контроллере) не совсем понятно.

Например из вида в $data['table'] передаётся название таблицы "book". Хотя сама таблица в базе называется #__lender_books.

Далее есть файл модели models/book.php

Код
class LendrModelsBook extends LendrModelsDefault
{

  /**
  * Protected fields
  **/
  var $_book_id     = null;
 
  var $_user_id     = null;
 
  var $_library_id  = null;

  var $_pagination  = null;

  var $_total       = null;

  var $_published   = 1;

  var $_waitlist    = FALSE;

  var $_wishlist    = FALSE;


  function __construct()
  {
    $app = JFactory::getApplication();
    $this->_book_id = $app->input->get('id', null);
   
    parent::__construct();       
  }
 
  /**
  * Builds the query to be used by the book model
  * @return   object  Query object
  *
  *
  */
  protected function _buildQuery()
  {
    $db = JFactory::getDBO();
    $query = $db->getQuery(TRUE);

    $query->select('b.book_id, b.user_id, b.isbn, b.title, b.author, b.summary, b.pages,
                    b.publish_date, b.lent, b.lent_date, b.due_date');
    $query->from('#__lendr_books as b');

    $query->select('w.waitlist_id, w.user_id as borrower_id');
    $query->leftjoin('#__lendr_waitlists as w on w.book_id = b.book_id AND w.fulfilled = 0');

    $query->select('l.name as borrower');
    $query->leftjoin('#__users as l on l.id = b.lent_uid');

    $query->select('u.name as waitlist_user');
    $query->leftjoin('#__users AS u on u.id = w.user_id');

    return $query;
  }

  public function getItem()
  {
    $book = parent::getItem();

    $reviewModel = new LendrModelsReview();
    $reviewModel->set('_book_id',$book->book_id);
    $book->reviews = $reviewModel->listItems();

    return $book;
  }

  /**
  * Builds the filter for the query
  * @param    object  Query object
  * @return   object  Query object
  *
  */
  protected function _buildWhere(&$query)
  {

    if(is_numeric($this->_book_id))
    {
      $query->where('b.book_id = ' . (int) $this->_book_id);
    }

    if(is_numeric($this->_user_id))
    {
      $query->where('b.user_id = ' . (int) $this->_user_id);
    }

    if(is_numeric($this->_library_id))
    {
      $query->where('b.library_id = ' . (int) $this->_library_id);
    }

    if($this->_waitlist)
    {
      $query->where('w.waitlist_id <> ""');
    }

    $query->where('b.published = ' . (int) $this->_published);

    return $query;
  }

  /**
  * Lend the book
  * @param    array   Data array of book
  * @return   object  The book object loaned
  */
  public function lend($data = null)
  {
    $data = isset($data)? $data : JRequest::get('post');

    if (isset($data['lend']) && $data['lend']==1)
    {
      $date = date("Y-m-d H:i:s");

      $data['lent'] = 1;
      $data['lent_date'] = $date;
      $data['lent_uid'] = $data['borrower_id'];

      $waitlistData = array('waitlist_id'=>$data['waitlist_id'], 'fulfilled' => 1, 'fulfilled_time' => $date, 'table' => 'Waitlist');
      $waitlistModel = new LendrModelsWaitlist();
      $waitlistModel->store($waitlistData);
    } else {
      $data['lent'] = 0;
      $data['lent_date'] = NULL;
      $data['lent_uid'] = NULL;

    }
   
    $row = parent::store($data);   
   
    return $row;

  }

  /**
  * Delete a book
  * @param int      ID of the book to delete
  * @return boolean True if successfully deleted
  */
  public function delete($id = null)
  {
    $app  = JFactory::getApplication();
    $id   = $id ? $id : $app->input->get('book_id');

    $book = JTable::getInstance('Book','Table');
    $book->load($id);

    $book->published = 0;

    if($book->store())
    {
      return true;
    } else {
      return false;
    }
  }
}


и ещё как оказалось есть файлы, как я понял, отвечающие за сами таблицы.
В данном случае файл tables/book.php
КОторый как я понял отвечает за операцию над той или иной таблицей.

Код
class TableBook extends JTable
{                     
  /**
  * Constructor
  *
  * @param object Database connector object
  */
  function __construct( &$db ) {
    parent::__construct('#__lendr_books', 'book_id', $db);
  }
}


есть кстати ещё один файл models/default.php. Тоже не совсем понятно что он делает.

Код
function __construct()
  {

    parent::__construct();
  }

  public function store($data=null)
  {   
    $data = $data ? $data : JRequest::get('post');
    $row = JTable::getInstance($data['table'],'Table');

    $date = date("Y-m-d H:i:s");

     // Bind the form fields to the table
    if (!$row->bind($data))
    {
        return false;
    }

    $row->modified = $date;
    if ( !$row->created )
    {
      $row->created = $date;
    }

    // Make sure the record is valid
    if (!$row->check())
    {
        return false;
    }
 
    if (!$row->store())
    {
        return false;
    }

    return $row;

  }

Я не прошу разжовывать для меня код и т.д.

Я прошу лишь помочь мне понять в какой последовательности и что вызывается. Оч рад за любую помощь, спасибо!
*

zomby6888

  • Завсегдатай
  • 1473
  • 171 / 3
Цитировать
index.php?option=com_lendr&controller=add&format=raw&tmpl=component',

Здесь написано не по стандартам. В компонентах по умолчанию контроллер вызывается через параметр task:

index.php?option=mycomponent&task=add&format=raw&tmpl=component'

вызовет метод add(), контроллера по умолчанию:

index.php?option=mycomponent&task=mycontroller.add&format=raw&tmpl=component'

вызовет метод add контроллера mycontroller

Цитировать
Например из вида в $data['table'] передаётся название таблицы "book". Хотя сама таблица в базе называется #__lender_books.

Этот параметр используется для создания объекта класса JTable

JTable::getInstance('book','Table');

Создает экземпляр класса TableBook. Описания классов лежат в папке tables. models/default.php - тут вообще непонятно что, возможно код неполный, возможно это просто мусор. Вы понимаете что нибудь в ООП? А то мы тут может зря стараемся?
интернет-блог: http://websiteprog.ru
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
В ООП слава богу понимаю, просто никогда не сталкивался с API Joomla. Там что то всё запутано.
*

robert

  • Живу я здесь
  • 4974
  • 457 / 20
Начните изучение с точки входа компонента и все будет понятно. У вас это /com_lendr/lendr.php.
Не будь паразитом, сделай что-нибудь самостоятельно!
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Я так и сделал в самом начале)
Иначе бы я вообще не знал бы даже с чего начать))
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Мне кстати так и никто не подсказал последовательность действий, которые происходят в компоненте.
Там можно как нибудь отладиться, чтобы расставить брэйк-пойнты и понять последовательно что там происходит?
*

Aleks.Denezh

  • Живу я здесь
  • 3401
  • 428 / 4
Мне кстати так и никто не подсказал последовательность действий, которые происходят в компоненте.
Там можно как нибудь отладиться, чтобы расставить брэйк-пойнты и понять последовательно что там происходит?
http://ссылка вырезана, так как домен распространяет вирусы/blog/joomla/printsip-raboty-mvc-komponenta-v-joomla.html
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Спасибо конечно, но та статья старая и для старой версии Joomla. У меня Joomla 3.2
Думаете там ничего не изменилось по сути?
*

robert

  • Живу я здесь
  • 4974
  • 457 / 20
Спасибо конечно, но та статья старая и для старой версии Joomla. У меня Joomla 3.2
Думаете там ничего не изменилось по сути?
^-^ Интересно, вы там все поняли? Скорее всего, не все, иначе не было бы этого вопроса.
Не будь паразитом, сделай что-нибудь самостоятельно!
*

Aleks.Denezh

  • Живу я здесь
  • 3401
  • 428 / 4
Спасибо конечно, но та статья старая и для старой версии Joomla. У меня Joomla 3.2
Думаете там ничего не изменилось по сути?
С 1.6 ветки принцип работы MVC компонента и последовательности работы его в Joomla не меняется! Статья подходит как для Joomla 1.6, так и для 2.5.х так и для 3.х.х веток..
*

broadcast77

  • Осваиваюсь на форуме
  • 27
  • 0 / 0
Ок. Почитал статью, очень полезно! Спасибо всем за помощь!
Не факт конечно, что больше от меня вопросов не будет, но хотя бы теперь всё более менее логично встало на свои места   ^-^
Чтобы оставить сообщение,
Вам необходимо Войти или Зарегистрироваться
 

Модель для представления, которое показывает списки данных разных типов

Автор borro

Ответов: 27
Просмотров: 1351
Последний ответ 06.05.2020, 11:57:12
от Septdir
Не работает setState

Автор platonische

Ответов: 29
Просмотров: 1198
Последний ответ 25.03.2019, 17:57:13
от robert
Не могу найти, где то подключается mootools

Автор Kasyanov

Ответов: 11
Просмотров: 1201
Последний ответ 20.08.2018, 01:08:11
от Kasyanov
Не могу записать SQL в терминах db query-&amp;gt;

Автор tm2010

Ответов: 2
Просмотров: 796
Последний ответ 16.04.2018, 18:00:30
от robert
Добавить функцию в модель FRONT END

Автор platonische

Ответов: 6
Просмотров: 945
Последний ответ 27.11.2017, 12:29:05
от platonische