I created a module that will allow certain user groups to create a request in the CMS.Any logged in user can access the module.
When user visit 'RequestModeule' in in CMS section in GRID CMS FIELDS I want to show him the requests he only sent not another customer requests. The system displays the requirements of all users and he see all.
How do I set the CMS FIELDS results to be displayed for the currently logged in user.
This is a ecommerce site and some customers want to return the product, some want to replace the product, some want to complain about the quality. I want to allow customers to submit a request themselves. I started with a simple model, so I will expand it when I solve big problems.
Here is my Model.
class Request extends DataObject
{
private static $db = [
'FullName' => 'Varchar',
'RequestText' => 'Text'
];
private static $has_one = [
'Photo' => Image::class
];
public function canView($member = null)
{
return Permission::check('VIEW_REQUEST', 'any', $member);
}
public function canEdit($member = null)
{
return Permission::check('EDIT_REQUEST', 'any', $member);
}
public function canDelete($member = null)
{
return Permission::check('DELETE_REQUEST', 'any', $member);
}
public function canCreate($member = null, $context = [])
{
return Permission::check('CREATE_REQUEST', 'any', $member);
}
/**
* #return \SilverStripe\Forms\FieldList
*/
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', TextField::create('FullName'));
$fields->addFieldToTab('Root.Main', TextField::create('RequestText'));
$fields->addFieldToTab('Root.Photos', $img = UploadField::create('Photo', 'Main photo'));
$img->setFolderName("products");
$img->setAllowedExtensions(["png", "jpg", "jpeg", "gif", "webp"]);
return $fields;
}
}
Request Controller
class Request_Controller extends ContentController implements PermissionProvider
{
function providePermissions(){
return array(
"CREATE_REQUEST" => "Create REQUEST",
"EDIT_REQUEST" => "Edit REQUEST",
"VIEW_REQUEST" => "View REQUEST",
"DELTE_REQUEST" => "Delete REQUEST",
);
}
First of all, I don't see anything about connecting your Request class with a Member. If you want to only show the things a member has created, you need to somehow store the Members ID or something.
The most obvious way to do this would be a private static $has_one = ['CreatedBy' => Member::class].
(and during creation you'll have to put the member ID into CreatedBy. For example you can do protected function onBeforeWrite() { parent::onBeforeWrite(); $this->CreatedByID = Security::getCurrentUser()->ID; })
As for the GridField:
There are 2 ways to control what is displayed in a GridField:
GridFields 3rd argument is any SS_List instance, so you can filter or customize that any way you want. For example you can use Request::get()->filter('CreatedByID' => 13) to only show the objects created by member ID 13.
You can use canView on each Request object. If it returns false, it will not be shown. So you can do public function canView($member = null) { return $member && $member->ID === $this->CreatedByID && Permission::check('VIEW_REQUEST', 'any', $member); }
Related
I have an entity MultiChannel that has a OneToMany relation with SalesChannel.
The restriction is that MultiChannel cannot have 2 SalesChannels that have the same name property.
Initially I had created the Story below, but that will endup with SalesChannels that have the same name.
App/Tests/Story/MultiChannelStory
final class MultiChannelStory extends Story
{
public function build(): void
{
SalesChannelFactory::createMany(100);
MultiChannelFactory::createMany(50, function() {
return [
'salesChannel' => SalesChannelFactory::randomRange(1,3),
];
});
}
}
Then I created a SalesChannelStory as below:
App/Tests/Story/SalesChannelStory
final class SalesChannelStory extends Story
{
public function build(): void
{
$this->addToPool('name1', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[0]])->many(50));
$this->addToPool('name2', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[1]])->many(50));
$this->addToPool('name3', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[2]])->many(50));
$this->addToPool('name4', SalesChannelFactory::new(['name' => SalesChannelFactory::SALES_CHANNELS[3]])->many(50));
}
}
The intention was to do something as below on MultiChannelStory, in somewhat pseudo code, so that
I could insert only uniquely named SalesChannel into MultiChannel:
App/Tests/Story/MultiChannelStory
final class MultiChannelStory extends Story
{
public function build(): void
{
SalesChannelFactory::createMany(100);
MultiChannelFactory::createMany(50, function() {
return [
'salesChannel' => $this->getUniqueNamed(),,
];
});
}
}
private function getUniqueNamed(): \App\Entity\Onetomanybi|\Zenstruck\Foundry\Proxy
{
// get up to 4 SalesChannel without the property `name` being repeated.
$items = [SalesChannelStory::getRandom('name1'), SalesChannelStory::getRandom('name2')];
return $items;
//return SalesChannelStory::getRandom('name1');
}
But that does not work.
Note that MultiChannel has to have at least one SalesChannel, up to as many SalesChannel exists, or 4 currently.
I have a model managed via model admin, I want to add a description below the gridfield. Usually this is accomplished by setting ->setDescription('Note in here')
How do you do this when it is managed via the ModelAdmin?
<?php
class FormDropdownModelAdmin extends ModelAdmin {
private static $managed_models = array(
'HearAboutUsItem'
);
private static $url_segment = 'form-dropdown-items';
private static $menu_title = 'Form Dropdown Items';
}
You can overload the getEditForm method on your ModelAdmin and apply a description to the field.
public function getEditForm($id = NULL, $fields = NULL) {
$form = parent::getEditForm($id, $fields);
$form->Fields()->fieldByName('HearAboutUsItem')
->setDescription('This is my description');
return $form;
}
I have created a Model Admin called 'Clients'. Under the "Security" tab I created a new group called 'clients'. This Model Admin is managing just the clients and not other members.
When creating a new member in the CMS using a model admin, I want to automatically generate a password for them (instead of them having to create their own one) one for them and then email it to them.
What I want to happen:
After the staff member clicks "Add member" the password and password confirmation textboxs are automatically populated with the generated password. - This is the most ideal way I believe. - Then once the staff member clicks save it will send the client and email with the username and newly generated password.
Question is how do you do this?
ClientAdmin.php
<?php
class ClientAdmin extends ModelAdmin {
private static $menu_icon = 'themes/cadence/images/icons/person.png';
public $showImportForm = false;
private static $managed_models = array(
'Member'
);
private static $url_segment = 'clients';
private static $menu_title = 'Clients';
public function getList() {
$list = parent::getList();
$clientGroup = Group::get()->filter('code', 'clients')->first();
$list = $list->filter('Groups.ID', $clientGroup->ID);
return $list;
}
}
MemberClientExtension.php
<?php
class MemberClientExtension extends DataExtension implements PermissionProvider
{
private static $db = array(
);
public function providePermissions() {
return array(
'CLIENTS' => 'Can access the site as a client',
);
}
public function updateCMSFields(FieldList $fields) {
}
public function generatePasswordForClient(){
$plainPassword = $this->owner->create_new_password();
$encryptedPassword = $this->owner->encryptWithUserSettings($plainPassword);
// Need to set password in database here?
return $plainPassword;
}
public function sendClientWelcomeEmail() {
$email = new Email('email#gmail.com', 'email#gmail.com', 'New member sign up');
$email->setTemplate('NewClientSignUp');
$email->populateTemplate(array(
'Email' => $this->owner->Email,
'Password' => $this->generatePasswordForClient()
));
return $email->send();
}
public function onBeforeWrite()
{
parent::onBeforeWrite();
}
public function onAfterWrite()
{
parent::onAfterWrite();
// Seems to send 2x emails.. Only want to send one
$this->sendClientWelcomeEmail();
}
}
You should set temporary plain text password in SetPassword field, and manage the context when onBeforeWrite and onAfterWrite hooks are called.
class MemberClientExtension extends DataExtension
{
protected $sendWelcomeEmail = false;
...
// onBeforeWrite on extension is called after password is encrypted and set
public function validate(ValidationResult $validationResult) {
if (!$this->owner->isInDB()) {
$this->sendWelcomeEmail = true;
}
}
public function onAfterWrite() {
if ($this->sendWelcomeEmail) {
// reset for password change
$this->sendWelcomeEmail = false;
$password = $this->generatePasswordForClient();
$this->owner->changePassword($password);
$this->sendClientWelcomeEmail(array(
'Email' => $this->owner->Email,
'Password' => $password;
));
}
}
}
You could use the populateDefaults() function in your Member extension.
public function populateDefaults() {
$this->owner->changePassword($this->generatePasswordForClient());
}
But let me say this: This is a bad idea. You don't want to send plain text passwords over something as insecure as an email. To let the user to choose its own password is by far the better way.
I am very new in SilverStripe thats why, facing so many problem. I want to retrieve data from table and show them in a page template.I have created a modeladmin and from there i can insert records but i cant figure out how could i retrieve those data and show them in a page template? basically my codes are bellow....
mysite/code/SerialsCollection.php
<?php
class SerialsCollection extends DataObject {
private static $db = array(
'Title' => 'Varchar',
'Author' => 'Varchar',
'Publisher' => 'Varchar',
'PublicationYear' => 'Date',
);
private static $searchable_fields = array(
'Title',
'Author'
);
private static $field_labels = array(
'Title' => 'Title' // renames the column to "Cost"
);
private static $summary_fields = array(
'Title',
'Author',
'Publisher',
'PublicationYear',
);
public function canView($member = null) {
return Permission::check('CMS_ACCESS_MyAdmin', 'any', $member);
}
public function canEdit($member = null) {
return Permission::check('CMS_ACCESS_MyAdmin', 'any', $member);
}
public function canDelete($member = null) {
return Permission::check('CMS_ACCESS_MyAdmin', 'any', $member);
}
public function canCreate($member = null) {
return Permission::check('CMS_ACCESS_MyAdmin', 'any', $member);
}
}
and mysite/code/SerialsCollectionAdmin.php ...
<?php
class SerialsCollectionAdmin extends ModelAdmin {
private static $managed_models = array(
'SerialsCollection'
);
private static $url_segment = 'serials-collection';
private static $menu_title = 'Serials Collection';
public function getList() {
$list = parent::getList();
return $list;
}
now, I am able to insert new records, view all and edit particular record. But what i want to create a page template and show these records on that page. I have tried it this way....
mysite/code/SerialsCollectionPage.php
<?php
Class SerialsCollectionPage extends Page{
}
Class Serials_Collection_Page_Controller extends Page_controller{
public function SerialsCollections()
{
return DataObject::get("SerialsCollection");
}
}
themes/SLIS/templates/SerialsCollectionPage.ss
<% include Header %>
<div id="Content">
<h1>This is SerialsCollection Page</h1>
<% control SerialsCollection %>
<p>Title: $Title</p>
<p>Author: $Author</p>
<p>Publication Year:$PublicationYear</p>
<% end_control %>
</div>
<% include Footer %>
But I got nothing only if i write something into content on the page then the contents are coming.
Any help would be really appreciated.
in the Page_Controller:
if SerialsCollection has only one instance make sure you get that instance alone, and make sure you use a get function:
public function getSerials(){
return SerialsCollection::get()->First();// for one item
return SerialsCollection::get();//for an array (use only one of those)
}
the get() alone will return a collection (ArrayList) which you will have to loop
in the Template
if you used the First(one item):
$Serials.Title
will print the title or if you used the array:
<% loop $Serials %>
$Title
<% end_loop %>
Read Querying Data from http://doc.silverstripe.org/en/developer_guides/model/data_model_and_orm/ .
In your case you would get data from the dataobjects with:
$sc = SerialsCollection::get();
Also you should read this: http://doc.silverstripe.org/en/developer_guides/model/lists/
How do I add a button to the backend of the CMS that fires an action? I can display the button where I want using:
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldsToTab("Root.ButtonTest", array(
FormAction::create('doAction', 'Action button')
)
);
return $fields;
}
public function doAction()
{
//Do something
}
However the button added does nothing when clicked.
I've seen one example of how to put a button on the main action bar (next to save/publish) but that's not what I'm trying to do.
Looking at the only page of documentation I can find, do I need to do something within:
public function getCMSActions()
{
$actions = parent::getCMSActions();
//Something here?
}
It isn't very clear how to create the action that the button calls.
You'll have to extend/decorate LeftAndMain with your own extension and the action you want to call. Here's an example:
<?php
class MyExtension extends LeftAndMainExtension
{
private static $allowed_actions = array(
'doAction'
);
public function doAction($data, $form){
$className = $this->owner->stat('tree_class');
$SQL_id = Convert::raw2sql($data['ID']);
$record = DataObject::get_by_id($className, $SQL_id);
if(!$record || !$record->ID){
throw new SS_HTTPResponse_Exception(
"Bad record ID #" . (int)$data['ID'], 404);
}
// at this point you have a $record,
// which is your page you can work with!
// this generates a message that will show up in the CMS
$this->owner->response->addHeader(
'X-Status',
rawurlencode('Success message!')
);
return $this->owner->getResponseNegotiator()
->respond($this->owner->request);
}
}
Once you have written an extension like this, you'll have to apply it to LeftAndMain by adding the following to your mysite/_config/config.yml:
LeftAndMain:
extensions:
- MyExtension
That's it. Your doAction button should now actually do something!
Not sure if this is helpful, but here's how you can add action-buttons to a ModelAdmin.
(does reload the page)
...in the admin class:
public function getEditForm($id = null, $fields = null)
{
$form = parent::getEditForm($id, $fields);
$form
->Fields()
->fieldByName($this->sanitiseClassName($this->modelClass))
->getConfig()
->getComponentByType('GridFieldDetailForm')
->setItemRequestClass('MyGridFieldDetailForm_ItemRequest');
return $form;
}
MyGridFieldDetailForm_ItemRequest.php
class MyGridFieldDetailForm_ItemRequest extends GridFieldDetailForm_ItemRequest
{
function ItemEditForm()
{
$form = parent::ItemEditForm();
$formActions = $form->Actions();
$button = FormAction::create('myAction');
$button->setTitle('button label');
$button->addExtraClass('ss-ui-action-constructive');
$formActions->push($button);
$form->setActions($formActions);
return $form;
}
public function myAction(){ //do things }
}