I have the following tables
1. Environment
--------------
env_id
env_name
env_description
repo_id
2. Repository
--------------
repo_id
repo_name
repo_url
Now multiple environments can be associated with same repository. I am very new to Eloquent and so has a confusion that which kind of relation this is ? I have an api and I would like to return repo details when I access an environment endoint. So when I use Evironment::all(), I would like to get the associated Repository. How can I do this ?
I went through the examples given in the documentation, but it seems like I have a scenario which is not mentioned there.
That will be a One To Many(inverse) relationship.
//Environment Model
public function repository()
{
return $this->belongsTo('App\Repository');
}
//Repository Model
public function environments()
{
return $this->hasMany('App\Environment', 'repo_id');
}
Then you can return all the Environment with their relationship as follow:
Environment::with('repository')->get();
According to your description, it should be a one-to-many relationship between two tables. Therefore, in plain English sentences, it would be, the Repository has many Environments and the Environment model belongs to the Repository. Let's build up those two models.
Repository model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Repository extends Model
{
public function environments()
{
return $this->hasMany(Environment::class);
}
}
Environment model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Environment extends Model
{
public function repo()
{
return $this->belongsTo(Repository::class);
}
}
Notice: I name after Environment::repo() instead of Environment::repository().
If we called Environment::repository as a property on the Environment object inside a foreach loop, it would return null instead of Repository object. It may be eloquent's naming issue. To be honest, I don't know the reason so far. I'm using Laravel 7.
Once you're done with the creations of models, you can play with data using them. As you need to get the associated Repository object with Environment object, check out the following code:
<?php
$environments = Environment::all();
foreach ($environments as $environment) {
echo $environment->repo->repo_name . '<br>';
}
Related
I have a entity in my symfony/sonata application which is not persisted via doctrine orm. Instead i would like to fill the data for these entities on demand by calling an api ...
How can i connect this custom managed entity with my existing model which is managed by doctrine orm?
Is there a way to exchange the doctrine managing part with my custom api calls? I know there are some repository functions like findAll() findBy() and so on ... is the solution to overwrite this functions?
Another approaches?
Thanks
I had a similar use case. I ended up with a solution which is roughly the following.
1) Create a custom ModelManager class. In my case I extended the one provided for Doctrine (Sonata\DoctrineORMAdminBundle\Model\ModelManager), but you can also directly implement Sonata\AdminBundle\Model\ModelManagerInterface.
Override the methdods you need to change (e.g. create(), update(), delete()).
# MyCustomModelManager.php
namespace AppBundle\Admin;
use Sonata\DoctrineORMAdminBundle\Model\ModelManager;
class MyCustomModelManager extends ModelManager {
public function create($object){ // Your custom implementation }
public function create($object){ // Your custom implementation }
public function create($object){ // Your custom implementation }
}
2) Register your new model manager as a service (not needed if you use Symfony 3.3 with the default container configuration, which includes automatic configuration of classes as services)
# services.yml
...
AppBundle\Admin\MyCustomModelManager:
arguments: [ '#doctrine' ]
...
3) Configure your admin class to use your custom model manager, for example:
app.admin.myadmin:
class: AppBundle\Admin\MyAdmin
tags:
- { name: sonata.admin, manager_type: orm }
arguments: [~, AppBundle\Entity\MyEntity, ~]
calls:
- [ setModelManager, [ '#AppBundle\Admin\MyCustomModelManager' ]]
Hope it helps :)
In a class file I can get all records from another repository that is not mine
$allUsergroups = $this->feGroupRepository->findAll();
How to make custom function to acomplish something like this on such a repository in the most correct way?
// magic default function that takes a uid list (or array) as argument
$someUsergroups = $this->feGroupRepository->findSomeByUidList('2,4,6,8');
Or can I extent an existing repository with my own custom functions, in this case based on $query->in(list)?
You can create your own method in your extensionRepository.php class
you can use :
in($propertyName, $operand)
or
contains($propertyName, $operand)
Contrarily, the methods in() and contains() accept multi-value data types as arguments (e.g. Array, ObjectStorage).
take a look how some other extension are doing stuff. (like the tx_news extension)
or read some docs here :
https://docs.typo3.org/typo3cms/ExtbaseFluidBook/6-Persistence/3-implement-individual-database-queries.html
Yes, you can extend another class in TYPO3 without any need to change any other code. It´s called Dependency Injection in ExtBase context.
First, create a new repository class your_ext/Classes/Domain/Repository/FrontendUserRepository.php and add below content to it:
<?php
namespace Tillebeck\YourExt\Domain\Repository;
class FrontendUserRepository extends \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository {
/**
* #param array $uidList
* #return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
*/
public function findByUidList(Array $uidList)
{
$query = $this->createQuery();
//$query->getQuerySettings()->setRespectStoragePage(false);
$query->matching(
$query->in('uid', $uidList)
);
return $query->execute();
}
/**
* #return string
*/
protected function getRepositoryClassName()
{
return get_parent_class($this);
}
}
Here we have implemented your method findByUidList with the required argument $uidList which needs to be an array.
Because repositories resolve their model names by their own class name, we need to change the method getRepositoryClassName to return the parent class name, in this case TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository.
But this alone won't work. We need to tell ExtBase that every time we inject or initialize a TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository, either by PHPDocBlock annotation #inject or by the objectManager->get, then we really want to initialize our new repository. This is done in TypoScript.
config.tx_extbase.objects {
TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository {
className = Tillebeck\YourExt\Domain\Repository\FrontendUserRepository
}
}
You can also restrict your change to your own extension alone by replacing config.tx_extbase with plugin.tx_yourext.
Last step: clear ALL cache, and possibly delete all files in typo3temp directory.
Now in your controller (or other class) you can run below code.
$uidList = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', '2,4,6,8', true);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
$this->frontendUserRepository->findByUidList($uidList)
);
I have tested above solution in TYPO3 7.6 and it works. Dependency Injection has existed since version 6.1.
This is by my definition the must correct way, as you asked, to implement this feature in your own TYPO3 extension.
I created a generic user repository base class that provides reusable user management functionality.
public class UserRepository<TUser> where TUser : new, IUser
{
}
I have a concrete implementation of IUser called UserImpl, and corresponding mapping class UserImplMap : ClassMap<UserImpl> (they all are in the same namespace and assembly). I add the mapping using AddFromAssemblyOf . I also use this to create / generate the schema.
So far so good and things work as expected.
Now, in a different project, I needed a few additional properties in my IUser implementation class, so I implemented a new class UserImplEx : UserImpl. This class has the additional properties that I needed. Also, I created a new mapping class UserImplExMap : SubclassMap<UserImplEx>
Now when I create schema using this approach, I get two tables one for UserImpl and one for UserImplEx.
Is is possible to configure / code Fluent mapping in some way so that all the properties (self, plus inherited) of UserImplEx get mapped in a single table UserImplEx instead of getting split into two tables?
Alternatively, if I provide full mapping in UserImplExMap : ClassMap<UserImplEx>, then I do get the schema as desired, but I also get an additional table for UserImpl (because corresponding mapping is present in the UserRepository assembly). If I follow this approach, is there a way to tell AddFromAssemblyOf to exclude specific mapping classes?
Option 1
since you have inhertance here and want the correct type back NH has to store the type somewhere, either through the table the data is in or a discriminator.
If a discriminator column in the table does not matter then add DiscriminatorColumn("userType", "user"); in UserImplMap and DiscriminatorValue("userEx") in UserImplExMap
Option 2
class MyTypeSource : ITypeSource
{
private ITypeSource _inner = new AssemblyTypeSource(typeof(UserImplMap).Assembly);
public IEnumerable<Type> GetTypes()
{
return _inner.Where(t => t != typeof(UserImplMap)).Concat(new [] { typeof(UserImplExMap) });
}
public void LogSource(IDiagnosticLogger logger)
{
_inner.LogSource(logger);
}
public string GetIdentifier()
{
return _inner.GetIdentifier();
}
}
and when configuring
.Mappings(m =>
{
var model = new PersistenceModel();
PersistenceModel.AddMappingsFromSource(new MyTypeSource());
m.UsePersistenceModel(model);
})
I'm working on a web app using the Lithium Framework with a MongoDB database.
On one page of the application - I want to display data from multiple object types. I understand the concept of relationships (i.e. belongsTo, hasMany, etc.) between models. But, my questions has to do with Controller relationships.
For example, assume I have two objects named "People" and "Companies". I want to show specific information about Companies on a "people" view. I have done the following:
1) In the "People" model, I've added the following line:
public $belongsTo = array('Companies');
2) In the "PeopleController" file, I've also included a reference to the Companies Model, such as:
use app\models\Companies;
Now, within the PeopleController, I want to call a method in the CompaniesController file.
Do I access this by directly calling the CompaniesController file? Or, do I have to go thru the Company model.
In either case, I'll need help with the syntax. I'm having rouble figuring out the best way this should be called.
Thanks in advance for your help!
You should rethink your structure - you controller method should really grab all the resources you need for that view, it doesn't matter what they are.
So if you have a url '/people/bob' and you want to get the company data for Bob just add that to the view method of your People controller. Something like
People::first(array('conditions' => array('name' => 'Bob'), 'with' => 'Companies'));
You could instantiate a CompaniesController (maybe passing in $this->request to the 'request' option in the process) and then call the method in it. However, a better way to organize it is to move the common functionality from CompaniesController to Companies and call it from both places.
use app\models\Companies does not really make a "reference." It simply indicates that Companies really means app\models\Companies. I think an "alias" is a better way to think of it. See http://php.net/manual/en/language.namespaces.importing.php.
Example:
// in app/models/Companies.php
namespace app\models;
class Companies extends \lithium\data\Model {
public static function doSomething() {
// do something related to companies.
}
}
// in app/controllers/CompaniesController.php
namespace app\controllers;
use app\models\Companies;
class CompaniesController extends \lithium\action\Controller {
public function index() {
$result = Companies::doSomething();
return array('some' => 'data', 'for' => 'the view');
}
}
// in app/controllers/PeopleController.php
namespace app\controllers;
use app\models\Companies;
class PeopleController extends \lithium\action\Controller {
public function index() {
$result = Companies::doSomething();
return array('some' => 'data', 'for' => 'the view');
}
}
I am using a Module in yii, and the module will be used when a property of an application model is true.
How can I get all the model names available in my application so that i can establish relations on conditional basis between application models having the property and the module?
You can use below method to get class name:
public function modelName()
{
return __CLASS__;
}
and call it like this:
$model = new State();
echo $model->getModelName();