What is a framework? And what is Doctrine 2? [duplicate] - php

This question already has answers here:
What is a Web Framework? How does it compare with LAMP?
(3 answers)
Closed 8 years ago.
I know some HTML, PHP, CSS and MySQL. Something that I haven't got to grasps with yet is frameworks. I am trying my best to read what they are and what they do, but for the life of me I cannot understand it.
Please could somebody explain frameworks and Doctrine 2 in a very simple way, as I don't know where to start with them, but notice that they are certainly required.

I could tell you here what a framework is, but the answers to the question What is a software framework? already do it.
So, about Doctrine. It's an object relational mapper (ORM). It basically allows you to insert/update/select/delete an object in a relational database, or generate/update tables via classes.
Let's assume a simple Member table:
Usually, you would write a query to, for example, insert something in a table. Such as:
INSERT Member VALUES ('Andy', 'andy#example.com', 30);
What an ORM allows you to do, is to insert a mapped object into the table. The values in the table will be seen just as you would normally see them by inserting them via query.
Let's look at a very simple example of Doctrine in the Symfony framework:
namespace ExampleProject\MemberBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Member
* #ORM\Table()
* #ORM\Entity
*/
class Member {
/**
* #var integer
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
* #ORM\Column(name="email", type="string", length=255)
*/
private $email;
/**
* #var string
* #ORM\Column(name="age", type="integer", length=3)
*/
private $age;
/* getters and setters here */
}
The above class is mapped (annotated with DocBlocks) and represents our Member table, describing which parts will be seen as columns in the database. Simply said: the mapped variables inside the class will be visible as columns in the database. And you also can tell by mapping these variables, which datatype you want the columns to have (string/integer etc).
Now in my code, I'm able to call the Doctrine entity manager, create a new Member object, initiate the properties and save it into the database, in a nice object-oriented syntax:
$em = $this->getDoctrine()->getEntityManager();
$member = new Member;
$member->setId($id);
$member->setName($name);
$member->setEmail($email);
$member->setAge($age);
$em->persist($member);
$em->flush();
As you can see, all we need to do is call to save the object in the database. In the background, the ORM also performs a INSERT query (similarly to the one I mentioned above). You even could enable a setting to see the actual query executed.
Now this may look quite unnecessary and lots of work. But it will save you a lot of time. It is more object oriented from your source code point of view, and you will be able to maintain your (medium/large) application much better than without using an ORM. Furthermore, if you currently have MySQL as a database, but you would like to change it to e.g., PostgreSQL, you can do so with minimal changes to your code as your ORM will take care of the underlying queries.
So in essence, the ORM is a database abstraction layer with object-oriented syntax.

Related

Doctrine 2 - Relate from abstract class to abstract class

Alright. This question is kind of hard to describe. But here goes. I'll post some images first, just incase someone gets what I'm doing from this image;
A Block is an element that can be used to fill a webpage or blogpost. This can be images, text or forms. These Blocks are ContentBlocks. Block has a DiscriminatorColumn and DiscriminatorMap properties that are used to join the right Block table and create the underlying Block element. (i.e. an ImageContentBlock)
On the other hand we have Forms. Forms consist of FormBlocks. These are certain common Form elements. (TextField, PhoneField etc).
I want to be able to relate to the Content- or FormBlocks from either Page, Post or Form.
How can I achieve this in Doctrine?
I could add an entityType and entityId field to the Block class. But that would remove the object orientated style of programming. I would rather refer to the owning ContentEntity. But then again. I need to join or relate to the Blocks.
Not every ContentEntity has Blocks. So I cannot add this as an property of ContentEntity.
Now. I could off course use a ManyToMany relationship and go with a JoinTable. I guess that would always work. But I would have to join twice.
I think your problem isn't primarily about the data relations but about the fact that you want to avoid duplicate code. This results in your “Entity” being at the top of your hierarchy, only because it has a few common properties that each entity should have. (By the way, naming an entity “Entity” is a bit confusing.)
Maybe what you're looking for are Traits. So, instead of providing id and active through an entity, it could as well be a trait:
trait CmsEntity
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\Column(type="boolean")
*/
protected $active;
// add getters/setters and other code as you like
}
Now you can attach this trait to all the entities which should have the given properties.
/**
* #ORM\Entity
*/
class Page
{
use CmsEntity; // import the trait
/**
* #ORM\Column(type="text")
*/
private $header;
// etc.
}
This will make you free from the requirement of deriving all your entities from one master “Entity” which just carries some common properties.
And now you can create a direct relation between between “ContentEntity” and “Block” (1:n I'd guess), which is more logical.
There's also a nice article elaborating on using Doctrine with traits for further reading.

How to store system settings in entity

I'm currently doing system, which settings should be editable by admin. He cannot add them, but only choose/edit from existing one.
All the backend is done in Sonata.
Settings class:
class SystemSettings
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="key", type="string", nullable=true)
*/
private $key;
/**
* #ORM\Column(name="value", type="string", nullable=true)
*/
private $value;
}
Problem is that I have different value types to store. I have some booleans, lists, integers, etc. For example I want to display array of languages as a list, but when it comes to "posts on page" setting, user should be able to write down any integer he wants. Is there any proper way to store it and display?
The problem with using this method of storage is as you said, variable data types. Soon you will want nested configuration, and eventually you will be writing over complex queries to select and update embedded JSON strings (trust me, i know).
I can't give you an exact solution because it is a problem I am still trying to solve. However some solutions I have yet to explore include:
Using MongoDB. Because it stores data in JSON natively, it is fair more suited to storing arbitrary datatypes (within the range of scalar and arrays at least).
Or dynamic file configuration. Which is a writable file using XML, or JSON as a format to store arbitary data. A problem you might run into though is if the server software is run on multiple machines. However if you can implement the first solution, then this one is essentially the same.
In all cases, the configuration should be incorruptible in so far as if something is wrong, there should be static defaults for it to fall back on. I am looking into adapting the Symfony\Component\Config component to achieve this.

Doctrine possible to reverse engineer inverse associations?

I have database with about 100 tables and I'm using Doctrine 2 as my Data Mapper. I successfully generated entities for my tables, however, I noticed that many-to-one relationships didn't generate bidirectionally. Only many-to-one part of the relation generates, the one-to-many does not.
For instance in my Company entity I have
/**
* #var \User
*
* #ManyToOne(targetEntity="User")
* #JoinColumns({
* #JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $user;
but I don't have anything pointing to the Company entity in User.
I am aware that Doctrine doesn't do this OOTB it says so in their documentation but I was wondering if there is a way to get around this limitation.
Writing 300+ relations by hand is a task I don't want to undertake.
Is there perhaps an alternative Data Mapper library for PHP that can solve this for me?
Thanks in advance.
I ended up using Propel because it generated everything wonderfully, albeit I ended up with some very large files (14k LoC).
It seems there simply isn't a PHP ORM that does everything right.

Doctrine : One to one to one relation?

I'm making entities for a Symfony2 project at work.
I'm trying to make a system that controls the access to certain resources in function of an organisation (a company) and of a role. To sum it up, roles are the same for all the companies, but a company may make a resource available for a role, as another may not want to.
As for resources, they represent some actions and contents, such as the creation of this, the edition of that, and so on...
I attempted to solve this problematic with the following entity. It represents a one to one to one relationship between my three entities Organisation, Role and Resource.
I wanted to know if that kind of relation was possible/good, or if there is another way to manage resources.
/**
* #ORM\Entity
*/
class Organisation_Role_Resource
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\UserBundle\Entity\Organisation")
*/
private $organisation;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\UserBundle\Entity\Role")
*/
private $role;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Aurae\UserBundle\Entity\Resource")
*/
private $resource;
Do you have any piece of advice on how to solve this problem?
Is there another/better way to represent resources (which are, in fact, pages and links) and to manage their access?
While this might be quite valid approach you would be really reinventing the wheel.
Symfony2 has it all implemented already as 'Access Control Lists' or (ACL):
http://symfony.com/doc/current/cookbook/security/acl.html
Check it out.... I think it covers everything you need...

Getting associated entries in Doctrine 2

I've decided that it would be a good asset to get familiar with an ORM and went for Doctrine 2 as the ORM of choice.
I'm working on a test project to learn the basics of Doctrine. Although most people usually go with a blog, I've decided to make a basic app in which you can save and track orders. My database schema would be as follows:
User
id
name
Product
id
name
price
Sales_order
id
user_id
product_id
quantity
unit_price
Hence, my Order model looks like:
/**
* #Entity
* #Table(name="sales_order")
*/
class Order {
/**
* #Id
* #Column(type="integer", nullable=false)
* #GeneratedValue(strategy="AUTO")
*/
private $Id;
/**
* #OneToOne(targetEntity="User", inversedBy="user")
*/
private $user;
/**
* #OneToOne(targetEntity="Product", inversedBy="product")
*/
private $product;
/**
* #Column(type="integer", nullable=false)
*/
private $quantity;
}
Now, the question is, is there a simple way of accessing all the orders from the user model? Should I write DQL (doctrine query language) for these kind of basic stuff or is there a way to easily get associated entities? I mean, there wouldn't be any point to this otherwise, right? Also, am I doing these associations correctly? I'm really confused in this very basic model... Detailed help is really appreciated. Thank you.
Firstly, don't worry too much about the database design. You should design your entities and use the SchemaTool.
Now, the question is, is there a simple way of accessing all the orders from the user model?
Do you mean access all of the orders from the user model, or access all the orders associated to a user?
If you meant the former, well you are doing things wrong (see below). If you meant the later, you should setup a bi-directional relationship between orders and users. (BTW, it would be OneToMany not OneToOne as one user would likely have many orders).
I'm really confused in this very basic model...
I think what you having trouble with - along with many PHP programmers - is the fundamental understandings of the DataMapper pattern and ultimately Domain Driven Design as well. Remember, you are dealing with persistable objects, not database tables.
I cannot provide detailed information here because I'd be writing a book, hence this I would recommend you get a book on Domain Driven Design to help kick start with the principles. There are a few good online resources available, like a series of blog posts by Federico Cargnelutti, however they aren't specific to Doctrine 2.

Categories