Display elements on second level relationship in Nova Laravel using indexQuery - laravel-nova

I've 3 models
User has a hasmany relation (domains()) with Domain and this hasMany relation (mailboxes) with Mailbox
User.php
public function domains()
{
return $this->hasMany(Domain::class);
}
Domain.php
public function user()
{
return $this->belongsTo(User::class);
}
public function mailboxes()
{
return $this->hasMany(Mailbox::class, 'domain', 'domain');
}
Mailbox.php
public function domains()
{
return $this->belongsTo('App\Domain', 'domain', 'domain');
}
Code below work fine for get only mailboxes owned but if put in policies not work.
public function view(User $user, Mailbox $mailbox)
{
$domains = Domain::where('user_id', $user->id)->pluck('domain')->toArray();
return User::with([
'domains.mailboxes' => function ($builder) use ($domains) {
$builder->where('domain',$domains);
}
])->find($user);
}
I tried overrinding indexQuery on my Nova/Mailbox model, but not work. Retunr all mailboxes on database
public static function indexQuery(NovaRequest $request, $query)
{
$domains = Domain::where('user_id', $request->user()->id)->pluck('domain')->toArray();
return User::with([
'domains.mailboxes' => function ($builder) use ($domains) {
$builder->where('domain',$domains);
}
])->find($user);
if ($request->user()->is_super_admin) {
return $query;
} else {
return User::with([
'domains.mailboxes' => function ($builder) use ($domains) {
$builder->where('domain',$domains);
}
])->find($user);
}
}

I would add a hasManyThrough (documentation) relationship between User and Mailbox so you can pluck the mailboxes directly from the User model:
# Inside User model class
public function mailboxes()
{
return $this->hasManyThrough(Mailbox::class, Domain::class, 'user_id', 'domain', 'id', 'domain');
}
Then in your indexQuery you could return the user with all its mailboxes:
public static function indexQuery(NovaRequest $request, $query)
{
return $query->when(! $request->user()->is_super_admin, function ($builder) use ($request) {
// Or use the request() method helper instead of use
return $request->user()->with('mailboxes');
});
}

Related

Can`t make cascade select in z-song laravel-admin

Laravel Version: 5.8
Laravel-admin: 1.7.9
I can`t make cascade select
I have tables:
users: id, name
categories: id, name
categories_users: id, categories_id, user_id
models:
class User extends Authenticatable {
public function category()
{
return $this->belongsToMany(Categories::class, 'categories_users', 'categories_id');
}
}
class Categories extends Model {
public function users()
{
return $this->belongsToMany(User::class, 'categories_users');
}
}
I need cascade select:
$form->select('user_id', 'User')->options($seller)->load('categories_id', '/admin/api/users')->required();
$form->select('categories_id', 'Categories of user')->required();
but it not work !!!
Controller:
public function getData(Request $request){
$user_id = $request->get('q');
return User::find($user_id)->category()->get(['id', DB::raw('name as text')]);
}
public function getData(Request $request){
$user_id = $request->get('q');
$q = DB::table('categories_users')->where('user_id', $user_id)->pluck('categories_id');
$categories = Categories::whereIn('id', $q)->get(['id', DB::raw('name as text')]);
return $categories;
}
It work!

ZF2 TableGateway join

I am in the process of trying to learn OO/Zend Framework over standard PHP.. I want to scream and write a mysql query instead of using the TableGateway method.
I have been following tutorials and have successfully printed out a table and some fields, although with the way I have gone about doing this, I am totally lost in how I should make this a join with another table and print out some fields there.
For example.
Table Fields
customer Idx, Company
contact Idx, First_Name
This is my customersController where I assume the work is carried out
namespace Customers\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\DB\TableGateway\TableGateway;
class CustomersController extends AbstractActionController
{
protected $customersTable;
public function indexAction()
{
return new ViewModel(array('customer' => $this->getCustomersTable()->select()));
//return new ViewModel(array('customers' => $this->fetchJoin()->select()));
}
public function addAction()
{
}
public function editAction()
{
}
public function deleteAction()
{
}
public function getCustomersTable()
{
if (!$this->customersTable) {
$this->customersTable = new TableGateway (
'customer', //table name
$this->getServiceLocator()->get('Zend\DB\Adapter\Adapter')
);
}
return $this->customersTable;
}
}
Am I on the right track here?
If you need to make joins read about Zend\Db\Sql and Zend\Db\Select
which you can read about here
http://framework.zend.com/manual/2.0/en/modules/zend.db.sql.html
An example would be:
In your model(that extends the TableGateway or the AbstractTableGateway)
in Some function you can have something like(this is from a project) :
$sql = new \Zend\Db\Sql\Sql($this->getAdapter());
$select = $sql->select()
->from('event_related_events')
->columns(array())
->join('event_invitees', 'event_invitees.event_id =
event_related_events.related_event_id')
->where(array('event_related_events.event_id' => $eventId));
$selectString = $sql->getSqlStringForSqlObject($select);
$results = $this->getAdapter()->query($selectString, \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
Then you can loop over the results and do what you need to.
Taking a look at more powerful ORM like Doctrine or Propel may also help, but may be an overkill for a small/hobby project.
EDIT: Answer for what was asked in comments
For Using expression(if, case etc) directly you can use something like :
$sql->select()
->from('table')
->columns(array(
'sorter' => new Expression('(IF ( table.`something` >= 'otherthing', 1, 0))'),
'some_count' => new Expression('(count(*))'),
)
)
Explaining the last line in SQL terms, it would be:
count(*) AS some_count
So this is my controller, basically from the Album example but now it will display customers from the customer table.
<?php
namespace Customers\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Customers\Model\Customers;
use Customers\Form\CustomersForm;
class CustomersController extends AbstractActionController
{
protected $customersTable;
public function indexAction()
{
return new ViewModel(array(
'customer' => $this->getCustomersTable()->fetchAll(),
));
}
public function addAction()
{
}
public function editAction()
{
}
public function deleteAction()
{
}
public function getCustomersTable()
{
if (!$this->customersTable) {
$sm = $this->getServiceLocator();
$this->customersTable = $sm->get('Customers\Model\CustomersTable');
}
return $this->customersTable;
}
}
?>
The indexAction calls the getCustomersTable method which goes to the model (CustomersTable) and executes the "query" there.
<?php
namespace Customers\Model;
use Zend\Db\TableGateway\TableGateway;
class CustomersTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function getCustomers($id)
{
}
public function saveCustomers(customers $customers)
{
}
public function deleteCustomers($id)
{
}
}
?>
So from your example, I should be trying to implement this into the fetchAll in the model?
Thanks for the help.
$sql = new \Zend\Db\Sql\Sql($this->getAdapter());
$select = $sql->select()
->from('customer')
->columns(array())
->join('contact', 'contact.Idx = customer.Idx')
->where(array('contact.Idx' => $eventId));
$selectString = $sql->getSqlStringForSqlObject($select);
$results = $this->getAdapter()->query($selectString, \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);

Custom Widget In Orchard CMS Throw error

**Hi Friends,
I am try to create custom widget in Orchard to display Student detail it show in widget list in admin panel but throw error when click on save button when i try to use it.it shows error
error is:-
And my code is
Model Code is:-
public class studentPart :ContentPart<studentPartRecord>
{
public string Rollno { get { return Record.Rollno; } set { Record.Rollno =value; } }
public string Name { get { return Record.Name; } set { Record.Name = value; } }
public string Class { get { return Record.Class; } set { Record.Class = value; } }
}
public class studentPartRecord :ContentPartRecord
{
public virtual string Rollno { get; set; }
public virtual string Name { get; set; }
public virtual string Class { get; set; }
}
Migration code is:-
public int Create() {
// Creating table tb_Student_studentPartRecord
SchemaBuilder.CreateTable("tb_Student_studentPartRecord", table =>table
.ContentPartRecord()
.Column("Rollno", DbType.String)
.Column("Name", DbType.String)
.Column("Class", DbType.String)
);
return 1;
}
public int UpdateFrom1()
{
// Creating table tb_EmpData_EmpDataPartRecord
ContentDefinitionManager.AlterPartDefinition(typeof(studentPart).Name,
builder => builder.Attachable());
ContentDefinitionManager.AlterTypeDefinition("StudentWidget",
cfg => cfg
.WithPart("studentPart")
.WithPart("WidgetPart")
.WithPart("CommonPart")
.WithPart("IdentityPart")
.WithSetting("Stereotype", "Widget"));
return 2;
}
Driver code is:-
public class studentPartDriver :ContentPartDriver<studentPart>
{
protected override DriverResult Display(studentPart part, string displayType, dynamic shapeHelper)
{
return ContentShape("Parts_student",
() => shapeHelper.Parts_student(Rollno:part.Rollno,Name:part.Name,Class:part.Class));
}
//GET
protected override DriverResult Editor(studentPart part, dynamic shapeHelper)
{
return ContentShape("Parts_student_Edit",
() => shapeHelper.EditorTemplate(TemplateName: "Parts/student", Model: part, Prefix: Prefix));
}
//POST
protected override DriverResult Editor(studentPart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
Handler Code is:-
public class studentPartHandler :ContentHandler
{
public studentPartHandler(IRepository<studentPartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
Filters.Add(new ActivatingFilter<studentPart>("student"));
}
}
Please help me . Thanks in Advance
Change studentPart to StudentPart
Change studentPartRecord to StudentPartRecord
Change SchemaBuilder.CreateTable("tb_Student_studentPartRecord" to SchemaBuilder.CreateTable("StudentPartRecord"
As Bertrand says, your class names should be pascal case to comply with C# conventions, and the table name you pass to CreateTable should be the same as the record's class name. Orchard takes care of prefixing the final database table for you.

Custom validator, not being executed when used in a form

i have created a custom validator but when I want to use it, it seems that it is never executed!
the validator :
class sfTestUrlValidator extends sfValidatorUrl {
public function initialize($context, $parameters = null) {
// Initialize parent
parent::initialize($context);
}
public function execute(&$value, &$error) {
if($value == "http://www.librosweb.es/")
{
//$error = "noooooooooooooo";
return true;
}
else return false;
}
}
in the configure method of a form, i do like that :
public function configure() {
.....
....
'url' => new sfTestUrlValidator(),
You need to override sfValidatorBase::doClean method and not some not-existent execute method and throw exception intead of returning true/false. Have a look at any validator class, e.g. sfValidatorString. However in your case, I would simply use sfValidatorChoice with one choice
public function configure()
{
'url' => new sfValidatorChoice(array('choices' => array(
'your.website.url',
)));
}

Inline Interface implementation in Actionscript

Is something like this possible in Actionscript?
Java:
URLFetcherFactory.setCreator(
new IURLFetcherCreator() {
public IURLFetcher create() {
return new URLFetcher();
}
}
);
Actionscript:
?
I've been wondering about this and have been unable to find anything that indicates it's possible. Figured if it was possible, I'd be able to find an answer here. Thanks! Stackoverflow rocks!
You cannot create an instance of an interface. You can, however, create a factory class:
public class URLFetcherCreator : IURLFetcherCreator {
private var _cls : Class;
public URLFetcherCreator(Class cls) {
this._cls = cls;
}
public function create() : IURLFetcher
{
return new cls();
}
}
Alternatively, change setCreator to accept a Function that returns an IURLFetcher:
URLFetcherFactory.setCreator(
function() : IURLFetcher {
return new URLFetcher();
}
);
Try this:
URLFetcherFactory.setCreator(
new IURLFetcherCreator() {
public function create():IURLFetcher {
return new URLFetcher();
}
}
);
You can't use anonymous inner classes in AS3.
For special cases like callbacks you can use Function instead of anonymous inner classes.
Java:
interface Callback {
void done(String info);
}
class Service {
void process(Callback callback);
}
...
myService.process(new Callback() {
void done(String info) {
// trace(info);
}
}
AS3:
class Service {
public function process(callback:Function):void;
}
...
myService.process(function(info:String):void {
trace(info);
});

Resources