I'm new to a Contao project, and the only dev at the project....
A custom module is created. For this custom module there is a data entry form (defined in a php file in the dca folder), in which a user can enter all the data which is then stored in a custom table.
The code for the module follows the layout stated in the blogpost 'Create a custom module - the basics' (http://blog.qzminski.com/article/create-a-custom-module-the-basics.html).
I've seen a PHP page (in the templates folder) which gets all the data from the custom database table (gets autoinjected via a variable?) and formats that in a html table.
That is what is built so far.
Now what I want to do is to create a display page for an individual item. Normally that will be:
create a link in the existing html table (with the id of the record)
which links to a new page (so for instance
pagenamewhichidonotknow?id=34)
and on that page, receive the id which is sent by the link (get it from the querystring?),
get the data from the custom databasetable (don't know how)
and then create a nice page (do know how to do this ;-))
I realize this is a large question, but I really don't know where to start.
Googling shows me a lot of pages with this warning "This guite was written for Contao 2.x and a lot of it's information is outdated! Read with care and only use as a general-purpose guide." and other pages are in German, which is, despite having learned it for 3 years in highschool, not my usp.
Any help is appreciated.
I hope I get you well. To achieve what you want, you will need to create two frontend modules, listModule and detailsModule and two pages, listPage and detailsPage therefore create these two pages in the backend(site structure). You will add listModule to the listPage and the detailsModule to detailsPage.
Never hardcode the page id unless you have no option.
Lets start on how to link to the detailsPage by creating the listModule and adding it to the listPage
Create /system/modules/my_module/dca/tl_module.php
Add the following code and save
$GLOBALS['TL_DCA']['tl_module']['palettes']['my_module'] = '{title_legend},name,headline,type,linkToDetail;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID,space';
$GLOBALS['TL_DCA']['tl_module']['fields']['linkToDetail']=array(
'label' => &$GLOBALS['TL_LANG']['tl_module']['linkToDetail'],
'exclude' => true,
'inputType' => 'pageTree',
'foreignKey' => 'tl_page.title',
'eval' => array('fieldType'=>'radio'),
'sql' => "int(10) unsigned NOT NULL default '0'",
'relation' => array('type'=>'hasOne', 'load'=>'eager')
);
This will create a column in your custom table that you will use it later to access the page ID in the template
Run the install tool.
Work on any errors that may arise. If none, go to next
Create the frontend module according to this url Front end module
In the compile function do as below
protected function compile(){
$objItems = $this->Database->execute("SELECT * FROM my_custom_table");
if (!$objItems->numRows)
{
return;
}
$arrItems = array();
// Generate item rows
while ($objItems->next())
{
$objPage = \PageModel::findPublishedById($objItems->linkToDetail);
$arrItems[] = array
(
'linkToDetail' => $objPage->getFrontendUrl('itemId='.$objItems->id),
);
}
$this->Template->items = $arrItems;
}
please note the itemId parameter added to the url
Create a template /system/modules/my_module/templates/my_template.html5
and you will be able to access easily the items
<?php if($this->items): foreach ($this->items as $item): ?>
<div class="item">
<?php if ($item['linkToDetail']): ?>
Please take me to the details page<?php endif; ?>
</div>
<?php endforeach; endif; ?>
Now go to themes -> modules ->new module and create a new module. I am assuming you have followed the instructions in that link on how to add your module to your module list. Assuming you added to the miscellaneous group, select your module. You will see a page picker with label 'linkToDetail'. select the detailsPage you created in the beginning.
Go to articles -> listPage -> new select 'module' as the element type and the choose your listModule above. We are good here. preview your page and you should be good.
Now lets build the detailsModule and add it to the detailsPage
Follow all the steps above only that in the compile function of the details module, you will select the details data as follows``
$objItemDetails = $this->Database->execute("SELECT * FROM my_custom_table where id=".\Input::get('itemId'));
step 7,8 and 9 are same.
This will help in the case where details page changes in times of ID. It makes it dynamic enough.
Hope this helps
To get list of items in the frontend:
Step 1 / create a List-Module:
go to "themes"
click the gears-icon
create a new modul
give it a name
choose the modul-type from the dropdown
(the name of the model to choose should be like this:
"yourCustomModulNameList" or similar)
Step 2 / embed the new List-Module into an Article:
go to articles in the main-menu
edit the article which should contain the list
choose new content-element
choose "Modul" as type
select your named modul
... to create a display page for an individual item, the steps are nearly the same:
create a reader-modul
insert this reader-modul on a new page (in a new article)
tell the previous created list-modul where the reader-modul is
hope this helps :)
Related
This has been asked before but I'm going to be more precise with my question to hopefully get a better answer:
I have figured out how to add views to the PageNames class:
public const string WorkOrders = "WorkOrders";
and then to the projectNavigationProvider class to get them in to the navbar:
.AddItem(
new MenuItemDefinition(
PageNames.WorkOrders,
L("WorkOrders"),
url: "WorkOrders",
icon: "business",
requiredPermissionName: PermissionNames.Pages_WorkOrders
)
To get my main views added to the main navbar and working properly.
However, I have not figured out how to create a totally new menu to be used elsewhere. In the app I'm working on we have several pages that display all of the records in a particular table, Work Orders for example. But each record in each table should have several links to other pages for create, edit, details and delete.
One of my partners seems to have solved this problem on other pages by using modals and ajax calls to the controllers endpoints. It works fine for the Customers, which only require name and contact info., but I don't think a modal will work for creating, viewing or editing a Work Order becuse it requires adding line items and the associated data for each one of them etc... There's a lot to it. Lastly, it doesn't seem like the template is set up to be used that was as he wrote a lot of his own js to get it working.
Currently, the create, edit, and details views exist and I have links to them next to each record but I get errors when I try to use the link. Maybe I don't understand how the routing works? In the normal mvc template from VS the links have properties for specifying the controller and method and mvc handles the rest.
<a asp-action="Edit" asp-route-id="#item.WorkOrderID">Edit</a> |
<a asp-action="Details" asp-route-id="#item.WorkOrderID">Details</a> |
<a asp-action="Delete" asp-route-id="#item.WorkOrderID">Delete</a>
I'm getting the same error I had when trying to get the Work Orders page to load but had not added it to pagenames or navigationprovider, which makes me thing I just need to add the links to the navigationprovider class but I don't want a link the the WordOrders create page on the main menu, I want it on a mini menu next to the corresponding record. I have added the page to the pagenames class but am not sure how to create a separate menu for my main page.
public const string CreateWorkOrders = "CreateWorkOrders";
In reviewing the navigationprovider class I see:
context.Manager.MainMenu
and I'm thinking I must be able to create another menu and add items to it like this:
context.Manager.NewMenu.AddItem(....
but it looks like MainMenu is referenced in a class that I can't find or edit. Should I be creating another class defining the NewMenu so I would be able to configure it in the existing navigationprovider class or should I be creating a separate navigationprovider class for it?
Hopefully I've convinced everyone who looks at this that I have done plenty of research before reaching out for help. Even a link to some more detailed documentation would helpful.
You can add a new menu like this:
context.Manager.Menus.Add(WorkOrders, new MenuDefinition(WorkOrders, L(WorkOrders)));
Usage:
context.Manager.Menus[WorkOrders].AddItem(...)
I'm new to alchemy-cms.
I created a fresh install from the guides. I did not add any concept or structure.
Going to localhost:3000 I have to add the first user and after that I have a clean site.
When trying to add a new page, I have to select a type (page-layout?) and type in a name.
The Type combobox remains empty, and therefore the website don't allow me to add a page. What am I doing wrong? I think I'm missing something very obvious here.
I have looked allready in the source code, and running the following:
rails console
Alchemy::PageLayout.all
and this results in:
=> [{"name"=>"index", "unique"=>true, "elements"=>["article"], "autogenerate"=>["article"]}]
So I would guess the combobox should be filled with this item.
The index page layout is marked as unique, so it can only be added once per language. And as the so called language root page (the first most page in your page tree) already has this page layout, no new page can be created using this page layout.
In order to fix your problem you need to add another page layout to your page_layouts.yml file. It is good practice to add an standard page layout that is not unique (default) and can therefore be added multiple times per language.
I need to build a admin interface like this image show. In the past I use components for that purpose but now because the modules are generated trough admin-generator I don't know how to get this done. I check all this docs 1, 2, 3 but without any clue on how to do this. I also created a components.class.php under modules/sdriving_empresa/actions folder and include the component in the view include_component('sdriving_empresa') but get this error:
sfComponents initialization failed.
Any help?
Tabs and Partials, the easy way :)
One of the best possible javascripts for that purpose is Javascript Tabifier. Its easy
to install and play with it. You will find a lot of other Javascript and jQuery Tabbers, get the one you most like.
I would advise you to learn everything about symfony 1 partials in order to get the job easily done. Usually partials are a piece of code which is saved in an external file, and does is loaded later in any part of your code. Its like a variable with a lot of html and php code. Partials (the external files) allow also to receive input variables, so its easy to send them ids from related modules or tables.
Lets look at an example with Tabifier with two Tabs, information and Admin and two partials
editSuccess.php
$sModuleName = sfContext::getInstance()->getModuleName();
$sbasepathtabs = $sModuleName . '/tabs';
<div class='tabber' id='tabberglobal1'>
<div class='tabbertab' title='Information' >
<?php
include_partial($sbasepathtabs . '/_information/_information', array('form' => $form));
?>
</div>
<div class="tabbertab" title="Admin" >
<?php
include_partial($sbasepathtabs . '/_admin/_admin', array('form' => $form));
?>
</div>
</div>
Easily setup it:
Inside your module template folder, create the folder: /_tabs
Inside the folder /_tabs create the folder /_information and /_admin
Inside the folder /_tabs/_information create the file partial: _information.php
Inside the folder /_tabs/_admin create the file partial: _admin.php
Inside each one of those files partials write anything you want.
Those partials will receive the left variable form: array('form' => $form).
You can send to the partials more than one variable: array('form' => $form, 'variable2' => $formnumber2)
When you write a partial, in example the partial _information, you can easily get the form object and its values in the template with:
$id = $form->getObject()->getId();
For normal variables you wont need to call getObject.
Finally, take a deep look at the documentation of both things, symfony partials and Javascript Tabifier. They will solve you anything you need.
Backend Admin Generator:
Admin generator automatically generates all templates in the cache folder. Example:
cache\backend\prod\modules\autoTbPrueba1Backend\templates
cache\backend\prod\modules\autoTbPrueba1Backend\templates\indexSuccess.php
Most of its files are already partials, pay attention to the files who has the _ symbol in their name, they are partials. This means that most of the work is already done for you, and the only thing you will have to do is to override some of the partials (TbPrueba1Backend/list_header which is the file _list_header.php) or even the full template (indexSuccess.php) with the extended information you need.
In order to override backend generated templates and partials, you can copy those files to the template folder of your module:
apps\backend\modules\TbPrueba1Backend\templates
apps\backend\modules\TbPrueba1Backend\templates\indexSuccess.php
Set there any additional information you need, and if you dont see anything new while refreshing the web, remember to clear the symfony cache (symfony cc).
Once you have override the the templates and partials with the new information, the only thing you need now is to write/add those partials inside the div tabs created by your bootstrap framework as I described above.
For a good explanation of the admin generator:
Symfony 1.4 change admin generator actions or templates
http://www.slideshare.net/loalf/symfony-y-admin-generator
http://symfony.com/legacy/doc/jobeet/1_4/en/12?orm=Doctrine
You need the moduleName and the componentName in your include_component()
function include_component($moduleName, $componentName, $vars = array())
{
echo get_component($moduleName, $componentName, $vars);
}
Or maybe your module is in the wrong application. In that case, you may consider moving it in a plugin
I currently have a landing page /vouchers and then many pages linked to that for example /vouchers/1, /vouchers/2 etc.
I currently have the functionality that if this is entered /vouchers/1?offer=50 then the form on that page is sent with the offer included in the url.
Now I need to add the functionality so if /vouchers?offer=50 is entered, any page that is then navigated to, will keep these parameters. (for example /vouchers/1 should then include the offer from the url)
I see only one way.
store all "special" parameters in session
in any handler — if "special" parameters are in session — form new url with this parameters and redirect user there
Let me guess :
1. you have a model , named "Voucher"
2. In case you want to see the entry for , let's say , voucher#1 , you see URL voucher/1 (notice the singular form of the word 'voucher')
3. you assign the value of the offer by some interaction by user , for example - link or list . Let's say it's a link . Try this (HAML):
= link_to "Accept this offer and create a new voucher", new_voucher_path(:offer => #offer_value)
(in your case #offer_value = 50)
The following view (or partial ) will be able to read the value in :offer .
You can refer to this useful discusion .
I solved this, probably not in the best way. On the /voucher page, I added if statements to all the links, so if there's an offer in the url, the links are appended appropriately.
I have several static files(pages), which are basically copies of my website pages source code, with the content changed.
These files support my website, (keeping the same format) in various ways.
For example the menu part is:-
<body>
<div id="menu">
<ul class="level1" id="root">
etc
etc. until
</ul>
</div>
Unfortunately every month or so my menu bar changes and I have to update each static file manually.
As each of my static files have the same menu.
Is it possible to have one menu file which can be updated and have the static files load them automatically.
I plan to have several more static files. So this would be a great help if someone can suggest how to accomplish this.
Oh yes. Use some javascript magic to load the menu bar upon page load and keep it in menu.html.
One solution may be to use a spider (wget --recursive) to download generated pages directly from your application. One command, and you have the full copy of your site. (just add some useful options, like --convert-links, for example).
The other option may be to write an after_filter in your controller, and write the generated content to a file (not always, but for example when you add a parameter ?refresh_copy=1). Maybe just turning on page caching would be suitable? But the problem will be that you will not be able to trigger the controller action so easily.
If you don't want the whole site copied, just add some specific routes or controllers (/mirrorable/...) and run the spider on them, or just access them manually (to trigger saving the content in the files).
I ended up creating one controller without a model.
rails g controller staticpages
I then created a layout file which imported the individual changes to the layout, via a "yield" tied to a "content_for" in the view files(static files(pages) in the "view of staticpages" (for example abbreviations, aboutthissite etc etc).
The rest of the static file loaded with the usual "yield" in the layout. Works a treat. No more updating the menu bar all done automatically.
To get to the correct static file I created a route using:-
match 'static/:static_page_name'=> 'staticpages#show' (or in rails 2.x:-
map.connect 'static/:static_page_name', :controller=> "staticpages", :action=> "show"
"static_page_name" variable accepted anything after "/static/" in the url and passed it to the controller "staticpages" in which I set up a show action containing:-
def show
#static_page_name = params[:static_page_name]
allowed_pages = %w(abbreviations aboutthissite etc, etc,)
if allowed_pages.include?(#static_page_name)
render #static_page_name
else
redirect_to '/' #redirects to homepage if link does not exists
end
end
I then only had to change the links in the website. (e.g.<%= link_to " About This Site ", '/static/aboutthissite' %>)
and viola! its all working.