Silverstripe dynamic page types - php

Am litle confused with new project. Am working site for one courses school.
Course page:
Courses page is added via administration admin/pages/ and have own page type and data object. Course, CoursePage, CourseCategory. CoursePage has page model and controller where i have few methods for listing courses and categories. Also i have template CoursePage.ss and CoursePage_details.ss.
All courses has one course category.
Inside CoursePage_Controller i have two main methods:
public function details(SS_HTTPRequest $request)
public function ListAllCourses() {
return Course::get();
}
Adding new courses:
Adding new courses is done via admin model. I have CourseAdmin which extends ModelAdmin and all work good.
Displaying courses:
This is done via Course_Controller and Course_Page.ss and Course_Page_details.ss
Everything work fantastic but now problem is comming:
Problem:
My client want to create child pages inside Courses page and assign selected courses on a specific page.
So he want to create new child Web development courses page and want to loop only courses for web development on that page.
Here i have problem becouse am adding courses via admin model. Next, all that sub page must have own page type like WebDevelopmentPage where i will query and filter that courses by category.
So if client want to add new child page and want to assign courses to that child page he must call me becouse i must create new page type and new page template for all that page, for that new child page! That is realy bad...
if there is a way that I could to filter the information through subpages? Or any trick to system automticly create new page type?
Update:
Solution 1:
I try this and work ok, but i think this is a bad practice.
Inside Course data object i add new db field UrlSegment where user must map some url segment like on page url. With what i will filter all on one page
public function Courses()
{
if($this->URLSegment == "all-courses") {
return Courses::get();
}else {
$c = Courses::get()->filter(array(
'UrlSegment' => $this->URLSegment
))->sort('Featured', 'DESC');
return $c;
}
}

Related

Automatic Laravel routing for static pages

I have to maintain a site for a client, they had it made with Laravel, the most frequent requests from them are to create new static pages and the more I create them - the more I feel there are definitely better ways to implement them.
To create a static page I go to the admin panel, a menu "Static Pages", push a button "Create New" and there create an entry that goes into a database table. To make the static page show in the website I have to define it in a controller called "FrontEndController" like this:
public function some_page() {
$page = StaticPages::find(1);
return view('frontend.static_pages.some_page', compact('page'));
}
public function some_other_page() {
$page = StaticPages::find(2);
return view('frontend.static_pages.some_other_page', compact('page'));
}
...
Then define routes like this:
Route::get('some-page', 'FrontEndController#some_page')->name('static_page.some_page');
Route::get('some-other-page', 'FrontEndController#some_other_page')->name('static_page.some_other_page');
Now I always thought that you create an admin panel with a menu "Static Pages" and a button "Create New" so that you don't have to put any code manually, but seemingly the developer had other ideas...
So my question is how do you refactor a code like this so that you don't have to go through all of the repetitive process in any similar scenario and write code manually?
Btw I may need to sometimes send some generic params to different static pages and I want to keep the URLs the same as they are. Please, keep in mind that I'm not a very advanced user of Laravel or even PHP.
There is no need to add extra method and router for per page manually.
I think that is a matter of unexperienced developer ,
So, You need to refactor your codes like this.
Add one router and remove others.
Route::get('/static/{id}','FrontendController#index');
On your Controller.
public function index($id)
{
$page = StaticPages::find($id);
$theme = $page->theme; //assume you have save your html themplate name in your table via theme column
return view('frontend.static_pages.'.$theme, compact('page'));
}
Save url or slug in your database
Route::get('staticpage/{pagename}', 'FrontEndController#MethodName');
$page = StaticPages::where('url',$url)->first();
return view('YourStaticPage', compact('page'));

How to place two SilverStripe DefinedUserForms in home page

In SilverStripe how do you display two UserDefinedForms on one page?
I can display one UserDefinedForm on a page, but I am unable to display two on the same page. I would like to display two UserDefinedForms on my home page.
To display one UserDefinedForm I put this in my HomePage template:
<div id="contactForm" style="display: none;">
<% control ShowForm %>
<p><strong>$SiteConfig.FormHeading</strong></p>
$Form
<% end_control %>
</div>
Function ShowForm() is in my HomePage.php
function ShowForm() {
$get = DataObject::get_one('UserDefinedForm');
return new UserDefinedForm_Controller($get);
}
My problem is that I have created two forms, one is for contacts and one is for booking test drive. Both forms are UserDefinedForms, so if I write another function in HomePage.php example:
function ShowTestDriveForm(){
$get = DataObject::get_one('UserDefinedForm');
return new UserDefinedForm_Controller($get);
}
it will do nothing, or will render my first contacts form.
If I have created two UserDefinedForms what should the php for test drive form look like?
I tried to get it by URLSegment, but it gives me an internal server error:
public function showTestDriveForm() {
$record = DataObject::get_one("UserDefinedForm", "URLSegment = 'BookTestDrive'");
$results = new UserDefinedForm_Controller($record);
return $results;
}
How do I get the second UserDefinedForm to the homepage template?
You have a general misunderstanding on DataObjects, Pages & Controllers.
UserDefinedForm page type holds a form construction. They are pages, not separate objects (one does not query forms directly). The controller is the part that handles a request and contains an actual form handler.
You have also not specified a version, so I will assume SilverStripe v3.1
The basic thing you're looking for is:
public function ContactForm() {
return ModelAsController::controller_for($this->ContactPage())->Form();
}
public function TestDriveForm() {
return ModelAsController::controller_for($this->TestDrivePage())->Form();
}
Possibly with a bit more error checking.
This code also makes the assumption that your homepage has two has_one relations to UserDefinedForm pages named ContactPage and TestDrivePage.

custom admin module edit data not working properly

I am creating custom admin module where grid, edit, new, delete work as same as product grid. Everything working fine but when i click on grid row to edit item it redirects correctly but the all pages value is blank.
If you need any page please ask me here i can post the pages here
Normally in edit pages there is a form container, which contains a form, which has a method something like this:
protected function _prepareForm()
{
$form = new Varien_Data_Form();
$fieldset = $form->addFieldset(/* ...stuff... */);
$fieldset->addField(/* ...much more stuff... */);
$form->setUseContainer(true);
$this->setForm($form);
}
Without seeing any code I cannot guess what you have named things but at some point after adding fields you must also do:
$model = Mage::registry('some model you registered in a controller');
$form->setValues($model);

Dynamic form (switch entity) symfony2

I'm making a page for adverts. An advert can be of different types and therefore have different data. For instance, a vehicle would have the make and the model as extra data.
Right now, I've got one base doctrine entity Advert which contains the data that every advert requires. Different adverts in turn innherits this data (doctrine2 discriminatormap)
I need to populate the form dynamically (with ajax and symfony2 forms) if the user choose to create a vehicle ad I want to display the options for a vehicle advert. But I also need to change the entity to be of the form AdvertVehicle.
Is this possible? I did read the cookbook entry at the symfony2 homepage
"How to Dynamically Modify Forms Using Form Events":
This should be handled by making an AJAX call back to your application. In that controller, you can submit your form, but instead of processing it, simply use the submitted form to render the updated fields. The response from the AJAX call can then be used to update the view.
I understand how to make an ajax call back to my controller, and i understand how to use the form-events but how do I get the response of a rendered select-box (containing vehicle models for instance) back? With a new AbstractType? or formbuilder?
And then when the user actually submits the form I need to use the entity of the selected advert type. Can I change the entity according to the users choice in the form dynamically?
Edit
I checked the form innheritance out that's great, thank you. I extend the AdvertType and override the buildForm() method and before I add the items I need for the AdvertVehicleType I call the parent method.
Futher Explanation
Every advert entity contains price, description, title and category. Some adverts contains more, such as make and model. They are differentiated by the discriminatormap (doctrine2)
Example:
// -- Entity
class CarAdvert extends Advert {
protected $model;
protected $make;
}
// -- Entity
// -- This uses discriminator mapping
class Advert {
protected $title;
protected $description;
protected $price;
protected $category;
}
if the user selects the category cars I want to use the CarAdvert entity (for validation and persistance) if the user selects the house hold itemcategory I just want to use the normal Advert entity.
One major problem is still that I cannot figure out how to render the extended form via ajax. Any tips on this part? When the user selects car as a category, I want the form to be updated (via jQuery/ajax) but how do I make a controller that retrieves just the extended part of the form and sends the html back as a response (without using twig and rendering it in a view, is this possible)?
Solution:
See answer below!
Solution:
The solution to my problem was to create a few extra functions in the controller to solve the issue where I want to be able to change the entity and form "on the fly" from a selection by the user..
public function indexAction(Request $request)
{
$form = $this->getForm($request);
$form->handleRequest($request);
return array(
'form' => $form->createView(),
'request' => $request->request,
);
}
Where getForm retrieves the form, (e.g AdvertVehicleType for vehicles or AdvertType for a "default" advert).
The getForm method looks like this:
private function getForm(Request $request)
{
$categoryTitle = 'NONE';
$categoryId = $request->request->get('advert', false)['category'];
if ($categoryId) {
$categoryTitle = $this->getDoctrine()->getRepository('Bundle:Category')->find($categoryId)->getTitle();
}
return $this->createForm($this->getFormType($categoryTitle), $this->getEntity($categoryTitle));
}
here I retrieve the categoryID (that is selected in the form in the request) and retreives the formType with getFormTypeand the entity with getEntity.
private function getEntity($categoryTitle)
{
$entity = new Advert();
switch ($categoryTitle) {
case Category::CARS:
$entity = new AdvertCar();
}
return $entity;
}
private function getFormType($categoryTitle)
{
switch ($categoryTitle) {
case Category::CARS:
return new AdvertCarType();
default:
return new AdvertType();
}
}
To be able to update this "on the fly" with ajax (but it also works if the user tries to submit the form) I created another action in the controller.
This action renders the parts of the form that I want to update (on ajax call), I do this by actually picking out what I don't need in the form with twig setting the form objects to rendered like so:
{% do form.title.setRendered %}
(this is just an example I actually do this for all the form objects that I don't want to render.
I then simply just call:
{{ form_rest(form) }}
which will retrieve the "rest" of the form which is different for different categories.
Now let's say you have state and than town to select. First select the state then you render the towns for that state in twig (but then you can actually just render the part you need, e.g {{ form_row(form.towns) }} and you return this rendered template as a json-response and just put it in the div you want with jquery.
$html = $this->renderView('#Bundle/NewAddPage/filter_area.twig', array('form' => $form->createView()));
and then returning the $html variable in the response.
I hope this helps, and that the explanation is good enough, if not just make a comment and I'll update this with my answer!

Having an "edit" controller to deal with user editing? Does this design make sense?

Here is the flow:
User creates a text based post.
User edits a text based post (an edit page with the post info is displayed)
User submits the changes to the post (a request sent to the post controller)
Now, if I have MULTIPLE types of posts, I have to check in steps 2 and 3 that the user is indeed updating the RIGHT type of post because someone could very well alter the URL to edit a post of type A when it's really of type B. This leads to a lot of redundant code, such as ...
if(user is indeed the editor && the post type is correct) show the edit page
I think it would make a lot of sense to have an EDIT controller that does all the verification needed in the constructor (or maybe a base class?), and then calls the method. Have you encountered similar issues like this - and if not, does this make any design sense?
CodeIgniter is an MVC. That means that your controllers serve as an intermediate between your models (your data), and your view (front-end). "Edit" is an action that you do to objects, like data. Data objects should be organized within a controller, which calls the actual edit functions from the model.
I'm assuming you have a Post controller. At its core, it should have basic CRUD functions, like adding and editing posts. It should look something like this:
class Post extends CI_Controller
{
function __construct()
{
parent::__construct();
}
function index()
{
// List all posts, perhaps?
}
function add()
{
// Add a post
}
function edit($post_id)
{
// Edit a post
}
function view($post_id)
{
// View a post
}
}
That will give you the following pages:
http://example.com/post
http://example.com/post/add
http://example.com/post/view/1
http://example.com/post/edit/1
Checking for user permissions is its own chapter. If you are using a library like Tank Auth, you can check permissions like so:
if ($this->tank_auth->is_logged_in()) {
// Do stuff
}
That should go at the beginning of each function - or in the __construct(), if you want to DRY it up completely.
Good luck.

Categories