Skip to main content

Component Development - Frontend

Router Explanation

https://www.youtube.com/watch?v=zqyjRuVaT8M part 1 και το part 2!

Πρόκειται για το αρχείο που βρίσκεται στο frontend στο src/services/Router.php.

Κάνει το option=com_test&view=items σε search engine friendly URL. Όπως το ορίσουμε, συνήθως από το alias του μενού και έπειτα από τα alias της εφαρμογής μας. Π.χ. menu-alias/category-alias/subcategory-alias/item-alias

Προσθήκη alias

Προσθήκη alias στη βάση αν δεν υπάρχει ήδη και με το παρακάτω στο model του item στη save μετατρέπουμε αυτομάτως το όνομα του προϊόντος σε alias το οποίο θα εκμεταλλευτούμε για να κάνουμε τα SEF URL μπροστά:

OutputFilter::stringURLSafe("To onoma")

Αναφορά βιβλίου

https://www.dionysopoulos.me/book

Ajax Updates (Fetch)

Κατέβασε τα αρχεία: dynamic_fetch.zip

Αρχεία που πρέπει να προσθέσουμε κώδικα:

  • default.php
  • dynamic.js
  • ItemsController.php
  • joomla.asset.json

Main file (JavaScript)

async function addToTrolley(fred) {
let url = 'index.php?option=com_mycomponent&task=mycontroller.incoming&format=json';
const token = Joomla.getOptions('csrf.token', '');
let data = new URLSearchParams();
data.append('payload', fred);
data.append(token, 1);

const options = {
method: 'POST',
body: data
}

//makes request to My Component to retrieve the item record.
let response = await fetch(url, options);

if (!response.ok) {
throw new Error(Joomla.Text._('COM_MYCOMPONENT_JS_ERROR_STATUS') + `${response.status}`);
} else {
results = await response.json();
console.log(results);
return results;
}

Controller

public function incoming()
{
// Get the details of the required data
$payload = $this->app->input->get('payload', '', 'string');
$options = json_decode($payload, true);

// create an instance of the Model
$model = parent::getModel('mymodel','Site', $options);

// Get message from model to be passed back to the caller.
$response = new JsonResponse($model->data);
echo $response;
$this->app->close();//προτιμότερο από exit;
}

JSON Response

Joomla JsonResponse

echo new JsonResponse($response_data, Text::_('COM_DIANEMO_LOGIN_INVALID_LOGIN'), true);
$this->app->close();

Custom JSON Response

$response = [
'success' => true,
'data' => $data
];

echo json_encode($response, JSON_PRETTY_PRINT);
$this->app->close();//προτιμότερο από exit;

Message Queue

Μπορούμε να κάνουμε και:

$this->app->enqueueMessage("blabla",'info');
$this->app->enqueueMessage("blabla",'warning');
$this->app->enqueueMessage("blabla",'error');

Σε οποιοδήποτε σημείο θέλουμε και τα παίρνουμε με:

$messages = $app->getMessageQueue();

Ώστε να τα επιστρέψουμε πίσω στο response αν θέλουμε για πληροφορία - κάτι που κάνει αυτόματα το JsonResponse του Joomla.

GET MODEL DATA

Από Controller

$model = $this->getModel('Item');
$item = $model->getItem($id);

Από οπουδήποτε

use Joomla\CMS\Factory; use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
$app = Factory::getApplication();
$component = $app->bootComponent('com_example');
$factory = $component->getMVCFactory();
$model = $factory->createModel('Item', 'Administrator');
$id = 42;// Example ID you want to fetch.
$item = $model->getItem($id);// Fetch the item using the model's getItem method.
// Do something with the item.
if ($item) {// Process the item as needed.
} else { // Handle the error.
}

Εναλλακτικός τρόπος

// Ensure the necessary component model is loaded. BaseDatabaseModel::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR . '/models', 'ExampleModel');
// Get an instance of the model.
$model = BaseDatabaseModel::getInstance('Item', 'ExampleModel');
// Retrieve the item using the model's getItem method.
$item = $model->getItem($id);

Table code


$table = $this->getTable();
if ($table->load(['alias' => $data['alias'], 'catid' => $data['catid']])) {
$msg = Text::_('COM_CONTENT_SAVE_WARNING');
}

Table από οπουδήποτε


$article = Joomla\CMS\Table\Table::getInstance('Content', 'JTable', array());
$articleExists = $article->load($articleId);

Tables - Boot Component

Φόρτωση item με ID 1 από το component 'com_test':

// Boot the component and create the table object
$table = \Joomla\CMS\Factory::getApplication()->bootComponent('com_test')->getMVCFactory()->createTable('item', 'Administrator');

// The ID of the item you want to load
$id = 1;

// Load the item by its ID
$loaded = $table->load($id);

if ($loaded) {
// Item loaded successfully
// Access the item's properties
$itemData = $table->getProperties();
// Do something with the item data
echo "<pre>";
print_r($itemData);
echo "</pre>";
} else {
// Failed to load the item
echo "Failed to load item with ID $id.";
}

Επεξήγηση

  • bootComponent: Αρχικοποιεί το συγκεκριμένο component (com_test στην περίπτωση αυτή).
  • getMVCFactory: Παίρνει το MVC factory για το component.
  • createTable: Δημιουργεί ένα table object για τον συγκεκριμένο πίνακα (στην περίπτωση αυτή, item στο Administrator context).
  • load: Φορτώνει τα δεδομένα για το item με το συγκεκριμένο ID (στην περίπτωση αυτή, 1). Επιστρέφει true αν το item φορτώθηκε επιτυχώς, αλλιώς false.
  • getProperties: Ανακτά όλες τις ιδιότητες του φορτωμένου item ως associative array.

Μέθοδοι Table Classes

Στις table classes του Joomla υπάρχουν αρκετές μέθοδοι:

  1. load($keys = null, $reset = true): Φορτώνει ένα row από τη βάση και κάνει bind τα πεδία στο table instance.
  2. save($src, $orderingFilter = '', $ignore = ''): Κάνει bind και αποθηκεύει ένα row στη βάση.
  3. delete($pk = null): Διαγράφει ένα row από τη βάση βάσει primary key.
  4. bind($src, $ignore = ''): Κάνει bind ένα named array/hash σε αυτό το object.
  5. check(): Ελέγχει την ακεραιότητα των properties του instance πριν αποθηκευτούν.
  6. store($updateNulls = false): Αποθηκεύει τα δεδομένα του table instance στη βάση.
  7. reset(): Επαναφέρει τις ιδιότητες στις default τιμές.
  8. publish($pks, $state = 1, $userId = 0): Αλλάζει την κατάσταση δημοσίευσης.
  9. reorder($where = ''): Αναδιατάσσει τα rows βάσει του ordering field.
  10. getFields(): Επιστρέφει πίνακα με τα πεδία του table.
  11. getTableName(): Επιστρέφει το όνομα του πίνακα.
  12. getKeyName(): Επιστρέφει το όνομα του primary key field.
  13. getColumnAlias($alias): Παίρνει το πραγματικό column name για ένα alias.

Παράδειγμα χρήσης μεθόδων

// Boot the component and create the table object
$table = \Joomla\CMS\Factory::getApplication()->bootComponent('com_test')->getMVCFactory()->createTable('item', 'Administrator');

// Load the item with ID 1
$table->load(1);

// Check the item
if ($table->check()) {
// Modify a property
$table->title = 'New Title';

// Store the item back to the database
if ($table->store()) {
echo "Item successfully updated.";
} else {
echo "Failed to update item.";
}
} else {
echo "Failed to check item.";
}

// Reset the table instance
$table->reset();

// Delete the item with ID 1
if ($table->delete(1)) {
echo "Item successfully deleted.";
} else {
echo "Failed to delete item.";
}

// Bind new data to the table
$data = ['title' => 'Another New Title', 'description' => 'New Description'];
$table->bind($data);

// Save the new data to the table
if ($table->save($data)) {
echo "New item successfully saved.";
} else {
echo "Failed to save new item.";
}

Custom Toolbar Button

//attach to joomla toolbar the new order button
$toolbar = Joomla\CMS\Toolbar\Toolbar::getInstance('toolbar');
$norder_button = '<button class="btn btn-primary norder_btn" id="norder_button"><span class="icon-new" title="New Order"></span> New Order</button>';
$toolbar->appendButton('Custom', $norder_button);

Fetch στο Frontend

Στο frontend βάζεις ένα κουμπί σαν αυτό:

<div class="custom-button">δυναμικό κουμπί</div>

Και θα δουλέψουμε με fetch. Στο items tmpl default.php φτιάχνεις ένα καινούριο αρχείο στο media/com_test/js/dynamic.js.

Το προσθέτεις στο joomla.asset.json του media/com_test:

{
"name": "com_test.dynamic",
"type": "script",
"uri": "com_test/dynamic.js"
}

Και στο dynamic.js βάζεις αυτό:


document.addEventListener("DOMContentLoaded", () => {

var refreshButton = document.querySelector('.custom-button');

refreshButton.addEventListener("click", function () {
dynamicChange();
});

async function dynamicChange() {
let url = 'index.php?option=com_test&task=items.blabla&format=json';
const options = {
method: 'POST',
}

//makes request to My Component to retrieve the item record.
let response = await fetch(url, options);

if (!response.ok) {
throw new Error('error status' + response.status);
} else {
let data = await response.json();
console.log(data);
}
}
});

Πώς δουλεύει

index.php?option=com_test&task=items.blabla&format=json

Αυτό το link πάει στο controller items και ψάχνει για τη συνάρτηση blabla. Άρα στο controller θες μια συνάρτηση:

function blabla(){
echo json_encode('test');
exit;
}

Στο console.log αυτό θα πρέπει να σου επιστρέψει "test".

Κάνε αυτά και να ρθω να σου δείξω τα επόμενα και τι μπορούμε να πετύχουμε με αυτό. Στην ουσία είναι το ίδιο με το fetch που κάνατε, απλώς εδώ επιστρέφουμε απλώς ένα κείμενο "test".

Φόρτωση του script

Πάνω πάνω στο default.php γράφεις:

$wa->useScript('com_test.dynamic');

Για να φορτώσει το αρχείο. Εναλλακτικά θα μπορούσες να το γράψεις και κατευθείαν μέσα στο default.php ανοίγοντας <script></script> αλλά καλύτερα σε ξεχωριστό αρχείο.

Εναλλακτικά fetch με .then

fetch(file)
.then(x => x.text())
.then(y => myDisplay(y))
.catch(error => console.error('Error:', error));

Fetch και then αντί για await.

Useful Code - Load View από άλλο Component

class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
//This is needed to find the layout
$config = ['base_path' => JPATH_ADMINISTRATOR . "/components/com_contact"];

$record_id = 1;

$app = Factory::getApplication();

$app->input->set('id', $record_id);
$input = $app->input;

$fred = $app->bootComponent('com_contact')->getMVCFactory();
$view = $fred->createView('contact', 'administrator', 'html', $config);
$view->setModel($fred->createModel('contact', 'Administrator', config: $config), true);

$barney = $view->getModel('contact');
// $Barney needs an addFormField included here somehow, otherwise needs to be coded in the contactModel
// Form::addFormPath(JPATH_ADMINISTRATOR . '/components/com_contact/forms');

$view->setLayout('edit'); //If not set will look for file called default.php
$view->document = $this->document; // Needed to find webassets etc in the template
$view->display();

// parent::display($tpl);
}